#include "asterisk.h"
#include <pthread.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/options.h"
#include "asterisk/causes.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/app.h"
#include "asterisk/say.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/config.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/utils.h"
#include "asterisk/adsi.h"
#include "asterisk/devicestate.h"
#include "asterisk/monitor.h"
#include "asterisk/indications.h"
Go to the source code of this file.
Data Structures | |
struct | aauser |
struct | ast_bridge_thread_obj |
struct | holdeduser |
struct | parkeduser |
Defines | |
#define | AST_MAX_WATCHERS 256 |
#define | DEFAULT_FEATURE_DIGIT_TIMEOUT 500 |
#define | DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000 |
#define | DEFAULT_PARK_TIME 45000 |
#define | DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 |
#define | FEATURE_RETURN_HANGUP -1 |
#define | FEATURE_RETURN_KEEPTRYING 24 |
#define | FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER |
#define | FEATURE_RETURN_PASSDIGITS 21 |
#define | FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE |
#define | FEATURE_RETURN_STOREDIGITS 22 |
#define | FEATURE_RETURN_SUCCESS 23 |
#define | FEATURE_RETURN_SUCCESSBREAK 0 |
#define | FEATURE_SENSE_CHAN (1 << 0) |
#define | FEATURE_SENSE_PEER (1 << 1) |
#define | FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0])) |
Enumerations | |
enum | { AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0), AST_FEATURE_FLAG_ONPEER = (1 << 1), AST_FEATURE_FLAG_ONSELF = (1 << 2), AST_FEATURE_FLAG_BYCALLEE = (1 << 3), AST_FEATURE_FLAG_BYCALLER = (1 << 4), AST_FEATURE_FLAG_BYBOTH = (3 << 3) } |
Functions | |
static int | adsi_announce_park (struct ast_channel *chan, char *parkingexten) |
int | ast_autoanswer_login (struct ast_channel *chan, void *data) |
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) |
struct ast_channel * | ast_get_holded_call (char *uniqueid) |
int | ast_hold_call (struct ast_channel *chan, struct ast_channel *peer) |
static | AST_LIST_HEAD_STATIC (feature_list, ast_call_feature) |
int | ast_masq_autoanswer_login (struct ast_channel *rchan, void *data) |
int | ast_masq_hold_call (struct ast_channel *rchan, struct ast_channel *peer) |
int | ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout) |
Park a call via a masqueraded channel. | |
AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS,"Call Features Resource",.load=load_module,.unload=unload_module,.reload=reload,) | |
AST_MUTEX_DEFINE_STATIC (holding_lock) | |
AST_MUTEX_DEFINE_STATIC (parking_lock) | |
AST_MUTEX_DEFINE_STATIC (autoanswer_lock) | |
int | ast_park_call (struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout) |
Park a call. | |
char * | ast_parking_ext (void) |
Determine system parking extension Returns the call parking extension for drivers that provide special call parking help. | |
int | ast_pickup_call (struct ast_channel *chan) |
Pickup a call. | |
char * | ast_pickup_ext (void) |
Determine system call pickup extension. | |
void | ast_register_feature (struct ast_call_feature *feature) |
register new feature into feature_list | |
int | ast_retrieve_call (struct ast_channel *chan, char *uniqueid) |
int | ast_retrieve_call_to_death (char *uniqueid) |
AST_RWLOCK_DEFINE_STATIC (features_lock) | |
void | ast_unregister_feature (struct ast_call_feature *feature) |
unregister feature from feature_list | |
static void | ast_unregister_features (void) |
Remove all features in the list. | |
static int | autoanswer_exec (struct ast_channel *chan, void *data) |
static int | autoanswer_login_exec (struct ast_channel *chan, void *data) |
static void | autoanswer_reregister_extensions (void) |
static int | builtin_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
static int | builtin_automonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
static int | builtin_blindtransfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
static int | builtin_disconnect (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
static int | builtin_parkcall (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
support routing for one touch call parking | |
static int | check_compat (struct ast_channel *c, struct ast_channel *newchan) |
static void | check_goto_on_transfer (struct ast_channel *chan) |
static void * | do_autoanswer_thread (void *ignore) |
static void * | do_holding_thread (void *ignore) |
static void * | do_parking_thread (void *ignore) |
Take care of parked calls and unpark them if needed. | |
static int | feature_exec_app (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
exec an app by feature | |
static struct ast_call_feature * | find_dynamic_feature (const char *name) |
find a feature by name | |
static int | finishup (struct ast_channel *chan) |
static int | handle_autoanswer (int fd, int argc, char *argv[]) |
static int | handle_parkedcalls (int fd, int argc, char *argv[]) |
static int | handle_showfeatures (int fd, int argc, char *argv[]) |
static int | load_config (void) |
static int | load_module (void) |
static int | manager_park (struct mansession *s, const struct message *m) |
static int | manager_parking_status (struct mansession *s, const struct message *m) |
Dump lot status. | |
static int | metermaidstate (const char *data) |
metermaids callback from devicestate.c | |
static void | notify_metermaids (char *exten, char *context) |
Notify metermaids that we've changed an extension. | |
static void | park_add_hints (char *context, int start, int stop) |
Add parking hints for all defined parking lots. | |
static int | park_call_exec (struct ast_channel *chan, void *data) |
Park a call. | |
static int | park_call_full (struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, char *orig_chan_name) |
static int | park_exec (struct ast_channel *chan, void *data) |
Pickup parked call. | |
static void | post_manager_event (const char *s, char *parkingexten, struct ast_channel *chan) |
static const char * | real_ctx (struct ast_channel *transferer, struct ast_channel *transferee) |
Find the context for the transfer. | |
static int | reload (void) |
static int | remap_feature (const char *name, const char *value) |
static int | retrieve_call_exec (struct ast_channel *chan, void *data) |
static void | set_c_e_p (struct ast_channel *chan, const char *context, const char *ext, int pri) |
store context, priority and extension | |
static void | set_config_flags (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config) |
static void | set_peers (struct ast_channel **caller, struct ast_channel **callee, struct ast_channel *peer, struct ast_channel *chan, int sense) |
set caller and callee according to the direction | |
static int | unload_module (void) |
static void | unmap_features (void) |
Variables | |
static struct aauser * | aalot |
static int | adsipark |
static int | atxfernoanswertimeout |
static char * | autoanswer = "Autoanswer" |
static pthread_t | autoanswer_thread |
static char * | autoanswerlogin = "AutoanswerLogin" |
static struct ast_call_feature | builtin_features [] |
static struct ast_cli_entry | cli_features [] |
static struct ast_cli_entry | cli_show_features_deprecated |
static char | courtesytone [256] |
static char * | descrip |
static char * | descrip2 |
static char * | descrip3 |
static char * | descrip4 |
static int | featuredigittimeout |
static char * | holdedcall = "HoldedCall" |
static pthread_t | holding_thread |
static struct holdeduser * | holdlist |
static char | mandescr_park [] |
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 | parkedplay = 0 |
static int | parkfindnext |
static char | parking_con [AST_MAX_EXTENSION] |
static char | parking_con_dial [AST_MAX_EXTENSION] |
static char | parking_ext [AST_MAX_EXTENSION] |
static int | parking_offset |
static int | parking_start |
static int | parking_stop |
static pthread_t | parking_thread |
static struct parkeduser * | parkinglot |
static int | parkingtime = DEFAULT_PARK_TIME |
static char | parkmohclass [MAX_MUSICCLASS] |
static char | pickup_ext [AST_MAX_EXTENSION] |
static char * | registrar = "res_features" |
static char | showautoanswer_help [] |
static char | showfeatures_help [] |
static char | showparked_help [] |
static char * | synopsis = "Answer a parked call" |
static char * | synopsis2 = "Park yourself" |
static char * | synopsis3 = "Log in for autoanswer" |
static char * | synopsis4 = "Autoanswer a call" |
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 72 of file res_features.c.
#define DEFAULT_FEATURE_DIGIT_TIMEOUT 500 |
#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000 |
#define DEFAULT_PARK_TIME 45000 |
#define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 |
#define FEATURE_RETURN_HANGUP -1 |
#define FEATURE_RETURN_KEEPTRYING 24 |
Definition at line 548 of file res_features.c.
Referenced by ast_feature_interpret(), and feature_exec_app().
#define FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER |
#define FEATURE_RETURN_PASSDIGITS 21 |
Definition at line 545 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 547 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 550 of file res_features.c.
Referenced by ast_bridge_call(), ast_feature_interpret(), builtin_parkcall(), and feature_exec_app().
#define FEATURE_SENSE_PEER (1 << 1) |
#define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0])) |
Definition at line 958 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().
anonymous enum |
AST_FEATURE_FLAG_NEEDSDTMF | |
AST_FEATURE_FLAG_ONPEER | |
AST_FEATURE_FLAG_ONSELF | |
AST_FEATURE_FLAG_BYCALLEE | |
AST_FEATURE_FLAG_BYCALLER | |
AST_FEATURE_FLAG_BYBOTH |
Definition at line 74 of file res_features.c.
00074 { 00075 AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0), 00076 AST_FEATURE_FLAG_ONPEER = (1 << 1), 00077 AST_FEATURE_FLAG_ONSELF = (1 << 2), 00078 AST_FEATURE_FLAG_BYCALLEE = (1 << 3), 00079 AST_FEATURE_FLAG_BYCALLER = (1 << 4), 00080 AST_FEATURE_FLAG_BYBOTH = (3 << 3), 00081 };
static int adsi_announce_park | ( | struct ast_channel * | chan, | |
char * | parkingexten | |||
) | [static] |
Definition at line 319 of file res_features.c.
References ADSI_JUST_CENT, ast_adsi_load_session(), ast_adsi_print(), and justify.
Referenced by park_call_full().
00320 { 00321 int res; 00322 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT}; 00323 char tmp[256]; 00324 char *message[5] = {NULL, NULL, NULL, NULL, NULL}; 00325 00326 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten); 00327 message[0] = tmp; 00328 res = ast_adsi_load_session(chan, NULL, 0, 1); 00329 if (res == -1) 00330 return res; 00331 return ast_adsi_print(chan, message, justify, 1); 00332 }
int ast_autoanswer_login | ( | struct ast_channel * | chan, | |
void * | data | |||
) |
Definition at line 2576 of file res_features.c.
References ast_channel::_state, ast_channel::appl, ast_add_extension2(), ast_answer(), ast_context_create(), ast_context_find(), ast_hangup(), ast_log(), AST_MAX_EXTENSION, ast_moh_start(), ast_mutex_lock(), ast_mutex_unlock(), AST_STATE_UP, ast_strdupa, ast_verbose(), aauser::chan, aauser::context, ast_channel::data, EVENT_FLAG_CALL, aauser::exten, exten, free, LOG_ERROR, LOG_NOTICE, LOG_WARNING, malloc, manager_event(), aauser::next, option_verbose, s, aauser::start, strdup, strsep(), and VERBOSE_PREFIX_2.
Referenced by ast_masq_autoanswer_login(), and autoanswer_exec().
02577 { 02578 /* We put the user in the parking list, then wake up the parking thread to be sure it looks 02579 after these channels too */ 02580 struct ast_context *con; 02581 char exten[AST_MAX_EXTENSION]; 02582 struct aauser *pu,*pl = NULL; 02583 char *s, *stringp, *aacontext, *aaexten = NULL; 02584 02585 s = ast_strdupa((void *) data); 02586 stringp=s; 02587 aacontext = strsep(&stringp, "|"); 02588 aaexten = strsep(&stringp, "|"); 02589 if (!aaexten) { 02590 aaexten = aacontext; 02591 aacontext = NULL; 02592 } 02593 if (!aaexten) { 02594 ast_log(LOG_WARNING, "AutoanswerLogin requires at least an extension!\n"); 02595 return -1; 02596 } else { 02597 if (!aacontext) { 02598 aacontext = "default"; 02599 } 02600 } 02601 02602 ast_mutex_lock(&autoanswer_lock); 02603 pu = aalot; 02604 while(pu) { 02605 if ((!strncasecmp(pu->exten, aaexten, sizeof(pu->exten)-1)) && (!strncasecmp(pu->context, aacontext, sizeof(pu->context)-1))){ 02606 if (pl) 02607 pl->next = pu->next; 02608 else 02609 aalot = pu->next; 02610 break; 02611 } 02612 pl = pu; 02613 pu = pu->next; 02614 } 02615 ast_mutex_unlock(&autoanswer_lock); 02616 if (pu) { 02617 ast_log(LOG_NOTICE, "Logout old Channel %s for %s@%s.\n",pu->chan->name, pu->exten, pu->context); 02618 manager_event(EVENT_FLAG_CALL, "AutoanswerLogout", 02619 "Channel: %s\r\n" 02620 "Uniqueid: %s\r\n" 02621 "Context: %s\r\n" 02622 "Exten: %s\r\n" 02623 ,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten); 02624 ast_hangup(pu->chan); 02625 free(pu); 02626 } 02627 pu = malloc(sizeof(struct aauser)); 02628 if (pu) { 02629 memset(pu, 0, sizeof(pu)); 02630 ast_mutex_lock(&autoanswer_lock); 02631 chan->appl = "Autoanswer"; 02632 chan->data = NULL; 02633 02634 pu->chan = chan; 02635 if (chan->_state != AST_STATE_UP) { 02636 ast_answer(chan); 02637 } 02638 02639 /* Start music on hold */ 02640 ast_moh_start(pu->chan, NULL, NULL); 02641 gettimeofday(&pu->start, NULL); 02642 strncpy(pu->exten, aaexten, sizeof(pu->exten)-1); 02643 strncpy(pu->context, aacontext, sizeof(pu->exten)-1); 02644 pu->next = aalot; 02645 aalot = pu; 02646 con = ast_context_find(aacontext); 02647 if (!con) { 02648 con = ast_context_create(NULL,aacontext, registrar); 02649 if (!con) { 02650 ast_log(LOG_ERROR, "Context '%s' does not exist and unable to create\n", aacontext); 02651 } 02652 } 02653 if (con) { 02654 snprintf(exten, sizeof(exten), "%s", aaexten); 02655 ast_add_extension2(con, 1, exten, 1, NULL, NULL, autoanswer, strdup((char *)data), free, registrar); 02656 } 02657 02658 ast_mutex_unlock(&autoanswer_lock); 02659 /* Wake up the (presumably select()ing) thread */ 02660 pthread_kill(autoanswer_thread, SIGURG); 02661 if (option_verbose > 1) 02662 ast_verbose(VERBOSE_PREFIX_2 "Autoanswer login from %s for %s@%s.\n", pu->chan->name, pu->exten, pu->context); 02663 manager_event(EVENT_FLAG_CALL, "AutoanswerLogin", 02664 "Channel: %s\r\n" 02665 "Uniqueid: %s\r\n" 02666 "Context: %s\r\n" 02667 "Exten: %s\r\n" 02668 ,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten); 02669 02670 return 0; 02671 } else { 02672 ast_log(LOG_WARNING, "Out of memory\n"); 02673 return -1; 02674 } 02675 return 0; 02676 }
int ast_bridge_call | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config | |||
) |
Bridge a call, optionally allowing redirection.
append the event to featurecode. we rely on the string being zero-filled, and not overflowing it.
Definition at line 1405 of file res_features.c.
References ast_channel::appl, ast_answer(), ast_cdr_alloc(), ast_cdr_appenduserfield(), ast_cdr_discard(), AST_CDR_FLAG_LOCKED, ast_cdr_init(), ast_cdr_merge(), ast_cdr_setdestchan(), ast_cdr_setuserfield(), ast_cdr_start(), ast_channel_bridge(), ast_channel_setoption(), ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OPTION, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_dtmf_stream(), ast_feature_interpret(), AST_FEATURE_PLAY_WARNING, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, ast_frfree, ast_indicate(), ast_indicate_data(), ast_log(), AST_OPTION_FLAG_REQUEST, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_channel::cdr, ast_cdr::channel, ast_option_header::data, ast_frame::data, ast_channel::data, ast_frame::datalen, ast_cdr::dstchannel, ast_bridge_config::end_sound, f, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_bridge_config::feature_timer, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_bridge_config::firstpass, ast_option_header::flag, ast_frame::frametype, free, LOG_DEBUG, LOG_WARNING, ast_option_header::option, option_debug, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), ast_bridge_config::play_warning, set_config_flags(), ast_bridge_config::start_sound, ast_bridge_config::start_time, ast_frame::subclass, ast_cdr::userfield, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.
Referenced by app_exec(), ast_bridge_call_thread(), ast_retrieve_call(), autoanswer_exec(), builtin_atxfer(), park_exec(), and try_calling().
01406 { 01407 /* Copy voice back and forth between the two channels. Give the peer 01408 the ability to transfer calls with '#<extension' syntax. */ 01409 struct ast_frame *f; 01410 struct ast_channel *who; 01411 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 01412 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 01413 int res; 01414 int diff; 01415 int hasfeatures=0; 01416 int hadfeatures=0; 01417 struct ast_option_header *aoh; 01418 struct ast_bridge_config backup_config; 01419 struct ast_cdr *bridge_cdr; 01420 01421 memset(&backup_config, 0, sizeof(backup_config)); 01422 01423 config->start_time = ast_tvnow(); 01424 01425 if (chan && peer) { 01426 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 01427 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 01428 } else if (chan) 01429 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 01430 01431 if (monitor_ok) { 01432 const char *monitor_exec; 01433 struct ast_channel *src = NULL; 01434 if (!monitor_app) { 01435 if (!(monitor_app = pbx_findapp("Monitor"))) 01436 monitor_ok=0; 01437 } 01438 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 01439 src = chan; 01440 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 01441 src = peer; 01442 if (monitor_app && src) { 01443 char *tmp = ast_strdupa(monitor_exec); 01444 pbx_exec(src, monitor_app, tmp); 01445 } 01446 } 01447 01448 set_config_flags(chan, peer, config); 01449 config->firstpass = 1; 01450 01451 /* Answer if need be */ 01452 if (ast_answer(chan)) 01453 return -1; 01454 peer->appl = "Bridged Call"; 01455 peer->data = chan->name; 01456 01457 /* copy the userfield from the B-leg to A-leg if applicable */ 01458 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) { 01459 char tmp[256]; 01460 if (!ast_strlen_zero(chan->cdr->userfield)) { 01461 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield); 01462 ast_cdr_appenduserfield(chan, tmp); 01463 } else 01464 ast_cdr_setuserfield(chan, peer->cdr->userfield); 01465 /* free the peer's cdr without ast_cdr_free complaining */ 01466 free(peer->cdr); 01467 peer->cdr = NULL; 01468 } 01469 01470 for (;;) { 01471 struct ast_channel *other; /* used later */ 01472 01473 res = ast_channel_bridge(chan, peer, config, &f, &who); 01474 01475 if (config->feature_timer) { 01476 /* Update time limit for next pass */ 01477 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time); 01478 config->feature_timer -= diff; 01479 if (hasfeatures) { 01480 /* Running on backup config, meaning a feature might be being 01481 activated, but that's no excuse to keep things going 01482 indefinitely! */ 01483 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) { 01484 if (option_debug) 01485 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n"); 01486 config->feature_timer = 0; 01487 who = chan; 01488 if (f) 01489 ast_frfree(f); 01490 f = NULL; 01491 res = 0; 01492 } else if (config->feature_timer <= 0) { 01493 /* Not *really* out of time, just out of time for 01494 digits to come in for features. */ 01495 if (option_debug) 01496 ast_log(LOG_DEBUG, "Timed out for feature!\n"); 01497 if (!ast_strlen_zero(peer_featurecode)) { 01498 ast_dtmf_stream(chan, peer, peer_featurecode, 0); 01499 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 01500 } 01501 if (!ast_strlen_zero(chan_featurecode)) { 01502 ast_dtmf_stream(peer, chan, chan_featurecode, 0); 01503 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 01504 } 01505 if (f) 01506 ast_frfree(f); 01507 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01508 if (!hasfeatures) { 01509 /* Restore original (possibly time modified) bridge config */ 01510 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01511 memset(&backup_config, 0, sizeof(backup_config)); 01512 } 01513 hadfeatures = hasfeatures; 01514 /* Continue as we were */ 01515 continue; 01516 } else if (!f) { 01517 /* The bridge returned without a frame and there is a feature in progress. 01518 * However, we don't think the feature has quite yet timed out, so just 01519 * go back into the bridge. */ 01520 continue; 01521 } 01522 } else { 01523 if (config->feature_timer <=0) { 01524 /* We ran out of time */ 01525 config->feature_timer = 0; 01526 who = chan; 01527 if (f) 01528 ast_frfree(f); 01529 f = NULL; 01530 res = 0; 01531 } 01532 } 01533 } 01534 if (res < 0) { 01535 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) 01536 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 01537 return -1; 01538 } 01539 01540 if (!f || (f->frametype == AST_FRAME_CONTROL && 01541 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 01542 f->subclass == AST_CONTROL_CONGESTION ) ) ) { 01543 res = -1; 01544 break; 01545 } 01546 /* many things should be sent to the 'other' channel */ 01547 other = (who == chan) ? peer : chan; 01548 if (f->frametype == AST_FRAME_CONTROL) { 01549 switch (f->subclass) { 01550 case AST_CONTROL_RINGING: 01551 case AST_CONTROL_FLASH: 01552 case -1: 01553 ast_indicate(other, f->subclass); 01554 break; 01555 case AST_CONTROL_HOLD: 01556 case AST_CONTROL_UNHOLD: 01557 ast_indicate_data(other, f->subclass, f->data, f->datalen); 01558 break; 01559 case AST_CONTROL_OPTION: 01560 aoh = f->data; 01561 /* Forward option Requests */ 01562 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 01563 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 01564 f->datalen - sizeof(struct ast_option_header), 0); 01565 } 01566 break; 01567 } 01568 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 01569 /* eat it */ 01570 } else if (f->frametype == AST_FRAME_DTMF) { 01571 char *featurecode; 01572 int sense; 01573 01574 hadfeatures = hasfeatures; 01575 /* This cannot overrun because the longest feature is one shorter than our buffer */ 01576 if (who == chan) { 01577 sense = FEATURE_SENSE_CHAN; 01578 featurecode = chan_featurecode; 01579 } else { 01580 sense = FEATURE_SENSE_PEER; 01581 featurecode = peer_featurecode; 01582 } 01583 /*! append the event to featurecode. we rely on the string being zero-filled, and 01584 * not overflowing it. 01585 * \todo XXX how do we guarantee the latter ? 01586 */ 01587 featurecode[strlen(featurecode)] = f->subclass; 01588 /* Get rid of the frame before we start doing "stuff" with the channels */ 01589 ast_frfree(f); 01590 f = NULL; 01591 config->feature_timer = backup_config.feature_timer; 01592 res = ast_feature_interpret(chan, peer, config, featurecode, sense); 01593 switch(res) { 01594 case FEATURE_RETURN_PASSDIGITS: 01595 ast_dtmf_stream(other, who, featurecode, 0); 01596 /* Fall through */ 01597 case FEATURE_RETURN_SUCCESS: 01598 memset(featurecode, 0, sizeof(chan_featurecode)); 01599 break; 01600 } 01601 if (res >= FEATURE_RETURN_PASSDIGITS) { 01602 res = 0; 01603 } else 01604 break; 01605 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01606 if (hadfeatures && !hasfeatures) { 01607 /* Restore backup */ 01608 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01609 memset(&backup_config, 0, sizeof(struct ast_bridge_config)); 01610 } else if (hasfeatures) { 01611 if (!hadfeatures) { 01612 /* Backup configuration */ 01613 memcpy(&backup_config, config, sizeof(struct ast_bridge_config)); 01614 /* Setup temporary config options */ 01615 config->play_warning = 0; 01616 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 01617 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 01618 config->warning_freq = 0; 01619 config->warning_sound = NULL; 01620 config->end_sound = NULL; 01621 config->start_sound = NULL; 01622 config->firstpass = 0; 01623 } 01624 config->start_time = ast_tvnow(); 01625 config->feature_timer = featuredigittimeout; 01626 if (option_debug) 01627 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer); 01628 } 01629 } 01630 if (f) 01631 ast_frfree(f); 01632 01633 } 01634 01635 /* arrange the cdrs */ 01636 bridge_cdr = ast_cdr_alloc(); 01637 if (bridge_cdr) { 01638 if (chan->cdr && peer->cdr) { /* both of them? merge */ 01639 ast_cdr_init(bridge_cdr,chan); /* seems more logicaller to use the destination as a base, but, really, it's random */ 01640 ast_cdr_start(bridge_cdr); /* now is the time to start */ 01641 01642 /* absorb the channel cdr */ 01643 ast_cdr_merge(bridge_cdr, chan->cdr); 01644 if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED)) 01645 ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */ 01646 01647 /* absorb the peer cdr */ 01648 ast_cdr_merge(bridge_cdr, peer->cdr); 01649 if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED)) 01650 ast_cdr_discard(peer->cdr); /* if locked cdrs are in peer, they are taken over in the merge */ 01651 01652 peer->cdr = NULL; 01653 chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */ 01654 } else if (chan->cdr) { 01655 /* take the cdr from the channel - literally */ 01656 ast_cdr_init(bridge_cdr,chan); 01657 /* absorb this data */ 01658 ast_cdr_merge(bridge_cdr, chan->cdr); 01659 if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED)) 01660 ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */ 01661 chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */ 01662 } else if (peer->cdr) { 01663 /* take the cdr from the peer - literally */ 01664 ast_cdr_init(bridge_cdr,peer); 01665 /* absorb this data */ 01666 ast_cdr_merge(bridge_cdr, peer->cdr); 01667 if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED)) 01668 ast_cdr_discard(peer->cdr); /* if locked cdrs are in chan, they are taken over in the merge */ 01669 peer->cdr = NULL; 01670 peer->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */ 01671 } else { 01672 /* make up a new cdr */ 01673 ast_cdr_init(bridge_cdr,chan); /* eh, just pick one of them */ 01674 chan->cdr = bridge_cdr; /* */ 01675 } 01676 if (ast_strlen_zero(bridge_cdr->dstchannel)) { 01677 if (strcmp(bridge_cdr->channel, peer->name) != 0) 01678 ast_cdr_setdestchan(bridge_cdr, peer->name); 01679 else 01680 ast_cdr_setdestchan(bridge_cdr, chan->name); 01681 } 01682 } 01683 return res; 01684 }
static void* ast_bridge_call_thread | ( | void * | data | ) | [static] |
Definition at line 280 of file res_features.c.
References ast_channel::appl, ast_bridge_call(), ast_cdr_reset(), ast_cdr_setdestchan(), ast_hangup(), ast_bridge_thread_obj::bconfig, ast_channel::cdr, ast_bridge_thread_obj::chan, ast_channel::data, free, and ast_bridge_thread_obj::peer.
Referenced by ast_bridge_call_thread_launch().
00281 { 00282 struct ast_bridge_thread_obj *tobj = data; 00283 00284 tobj->chan->appl = "Transferred Call"; 00285 tobj->chan->data = tobj->peer->name; 00286 tobj->peer->appl = "Transferred Call"; 00287 tobj->peer->data = tobj->chan->name; 00288 if (tobj->chan->cdr) { 00289 ast_cdr_reset(tobj->chan->cdr, NULL); 00290 ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name); 00291 } 00292 if (tobj->peer->cdr) { 00293 ast_cdr_reset(tobj->peer->cdr, NULL); 00294 ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name); 00295 } 00296 00297 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig); 00298 ast_hangup(tobj->chan); 00299 ast_hangup(tobj->peer); 00300 bzero(tobj, sizeof(*tobj)); /*! \todo XXX for safety */ 00301 free(tobj); 00302 return NULL; 00303 }
static void ast_bridge_call_thread_launch | ( | void * | data | ) | [static] |
Definition at line 305 of file res_features.c.
References ast_bridge_call_thread(), ast_pthread_create, and thread.
Referenced by builtin_atxfer().
00306 { 00307 pthread_t thread; 00308 pthread_attr_t attr; 00309 struct sched_param sched; 00310 00311 pthread_attr_init(&attr); 00312 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 00313 ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data); 00314 pthread_attr_destroy(&attr); 00315 memset(&sched, 0, sizeof(sched)); 00316 pthread_setschedparam(thread, SCHED_RR, &sched); 00317 }
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 1116 of file res_features.c.
References ast_copy_flags, AST_FLAGS_ALL, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verbose(), ast_call_feature::exten, exten, ast_call_feature::feature_mask, FEATURE_RETURN_KEEPTRYING, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_STOREDIGITS, FEATURE_SENSE_CHAN, ast_bridge_config::features_callee, ast_bridge_config::features_caller, FEATURES_COUNT, find_dynamic_feature(), ast_flags::flags, LOG_DEBUG, ast_call_feature::operation, option_debug, option_verbose, pbx_builtin_getvar_helper(), ast_call_feature::sname, strsep(), and VERBOSE_PREFIX_3.
Referenced by ast_bridge_call().
01117 { 01118 int x; 01119 struct ast_flags features; 01120 int res = FEATURE_RETURN_PASSDIGITS; 01121 struct ast_call_feature *feature; 01122 const char *dynamic_features; 01123 char *tmp, *tok; 01124 01125 if (sense == FEATURE_SENSE_CHAN) { 01126 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL); 01127 dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"); 01128 } else { 01129 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL); 01130 dynamic_features = pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"); 01131 } 01132 if (option_debug > 2) 01133 ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d dynamic=%s\n", chan->name, peer->name, sense, features.flags, dynamic_features); 01134 01135 ast_rwlock_rdlock(&features_lock); 01136 for (x = 0; x < FEATURES_COUNT; x++) { 01137 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) && 01138 !ast_strlen_zero(builtin_features[x].exten)) { 01139 /* Feature is up for consideration */ 01140 if (!strcmp(builtin_features[x].exten, code)) { 01141 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL); 01142 break; 01143 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) { 01144 if (res == FEATURE_RETURN_PASSDIGITS) 01145 res = FEATURE_RETURN_STOREDIGITS; 01146 } 01147 } 01148 } 01149 ast_rwlock_unlock(&features_lock); 01150 01151 if (ast_strlen_zero(dynamic_features)) 01152 return res; 01153 01154 tmp = ast_strdupa(dynamic_features); 01155 01156 while ((tok = strsep(&tmp, "#"))) { 01157 AST_LIST_LOCK(&feature_list); 01158 if (!(feature = find_dynamic_feature(tok))) { 01159 AST_LIST_UNLOCK(&feature_list); 01160 continue; 01161 } 01162 01163 /* Feature is up for consideration */ 01164 if (!strcmp(feature->exten, code)) { 01165 if (option_verbose > 2) 01166 ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok); 01167 res = feature->operation(chan, peer, config, code, sense, feature); 01168 if (res != FEATURE_RETURN_KEEPTRYING) { 01169 AST_LIST_UNLOCK(&feature_list); 01170 break; 01171 } 01172 res = FEATURE_RETURN_PASSDIGITS; 01173 } else if (!strncmp(feature->exten, code, strlen(code))) 01174 res = FEATURE_RETURN_STOREDIGITS; 01175 01176 AST_LIST_UNLOCK(&feature_list); 01177 } 01178 01179 return res; 01180 }
static struct ast_channel * ast_feature_request_and_dial | ( | struct ast_channel * | caller, | |
const char * | type, | |||
int | format, | |||
void * | data, | |||
int | timeout, | |||
int * | outstate, | |||
const char * | cid_num, | |||
const char * | cid_name | |||
) | [static, read] |
Definition at line 1225 of file res_features.c.
References ast_channel::_softhangup, ast_channel::_state, ast_call(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, ast_cdr_alloc(), ast_cdr_disposition(), ast_cdr_end(), ast_cdr_failed(), ast_cdr_init(), ast_cdr_setapp(), ast_cdr_start(), ast_cdr_update(), ast_channel_inherit_variables(), ast_check_hangup(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HANGUP, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_TEXT, ast_frfree, ast_hangup(), ast_indicate(), ast_log(), ast_read(), ast_request(), ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_set_callerid(), AST_STATE_UP, ast_verbose(), ast_waitfor_n(), ast_channel::cdr, ast_call_feature::exten, f, FEATURES_COUNT, ast_frame::frametype, ast_channel::hangupcause, len, LOG_NOTICE, LOG_WARNING, option_verbose, pbx_builtin_setvar_helper(), ast_frame::subclass, and VERBOSE_PREFIX_3.
Referenced by builtin_atxfer().
01226 { 01227 int state = 0; 01228 int cause = 0; 01229 int to; 01230 struct ast_channel *chan; 01231 struct ast_channel *monitor_chans[2]; 01232 struct ast_channel *active_channel; 01233 int res = 0, ready = 0; 01234 01235 if ((chan = ast_request(type, format, data, &cause))) { 01236 ast_set_callerid(chan, cid_num, cid_name, cid_num); 01237 ast_channel_inherit_variables(caller, chan); 01238 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name); 01239 if (!chan->cdr) { 01240 chan->cdr=ast_cdr_alloc(); 01241 if (chan->cdr) { 01242 ast_cdr_init(chan->cdr, chan); /* initilize our channel's cdr */ 01243 ast_cdr_start(chan->cdr); 01244 } 01245 } 01246 01247 if (!ast_call(chan, data, timeout)) { 01248 struct timeval started; 01249 int x, len = 0; 01250 char *disconnect_code = NULL, *dialed_code = NULL; 01251 01252 ast_indicate(caller, AST_CONTROL_RINGING); 01253 /* support dialing of the featuremap disconnect code while performing an attended tranfer */ 01254 ast_rwlock_rdlock(&features_lock); 01255 for (x = 0; x < FEATURES_COUNT; x++) { 01256 if (strcasecmp(builtin_features[x].sname, "disconnect")) 01257 continue; 01258 01259 disconnect_code = builtin_features[x].exten; 01260 len = strlen(disconnect_code) + 1; 01261 dialed_code = alloca(len); 01262 memset(dialed_code, 0, len); 01263 break; 01264 } 01265 ast_rwlock_unlock(&features_lock); 01266 x = 0; 01267 started = ast_tvnow(); 01268 to = timeout; 01269 while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) { 01270 struct ast_frame *f = NULL; 01271 01272 monitor_chans[0] = caller; 01273 monitor_chans[1] = chan; 01274 active_channel = ast_waitfor_n(monitor_chans, 2, &to); 01275 01276 /* see if the timeout has been violated */ 01277 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) { 01278 state = AST_CONTROL_UNHOLD; 01279 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n"); 01280 break; /*doh! timeout*/ 01281 } 01282 01283 if (!active_channel) 01284 continue; 01285 01286 if (chan && (chan == active_channel)){ 01287 f = ast_read(chan); 01288 if (f == NULL) { /*doh! where'd he go?*/ 01289 state = AST_CONTROL_HANGUP; 01290 res = 0; 01291 break; 01292 } 01293 01294 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) { 01295 if (f->subclass == AST_CONTROL_RINGING) { 01296 state = f->subclass; 01297 if (option_verbose > 2) 01298 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name); 01299 ast_indicate(caller, AST_CONTROL_RINGING); 01300 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) { 01301 state = f->subclass; 01302 if (option_verbose > 2) 01303 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name); 01304 ast_indicate(caller, AST_CONTROL_BUSY); 01305 ast_frfree(f); 01306 f = NULL; 01307 break; 01308 } else if (f->subclass == AST_CONTROL_ANSWER) { 01309 /* This is what we are hoping for */ 01310 state = f->subclass; 01311 ast_frfree(f); 01312 f = NULL; 01313 ready=1; 01314 break; 01315 } else if (f->subclass != -1) { 01316 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass); 01317 } 01318 /* else who cares */ 01319 } 01320 01321 } else if (caller && (active_channel == caller)) { 01322 f = ast_read(caller); 01323 if (f == NULL) { /*doh! where'd he go?*/ 01324 if (caller->_softhangup && !chan->_softhangup) { 01325 /* make this a blind transfer */ 01326 ready = 1; 01327 break; 01328 } 01329 state = AST_CONTROL_HANGUP; 01330 res = 0; 01331 break; 01332 } 01333 01334 if (f->frametype == AST_FRAME_DTMF) { 01335 dialed_code[x++] = f->subclass; 01336 dialed_code[x] = '\0'; 01337 if (strlen(dialed_code) == len) { 01338 x = 0; 01339 } else if (x && strncmp(dialed_code, disconnect_code, x)) { 01340 x = 0; 01341 dialed_code[x] = '\0'; 01342 } 01343 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) { 01344 /* Caller Canceled the call */ 01345 state = AST_CONTROL_UNHOLD; 01346 ast_frfree(f); 01347 f = NULL; 01348 break; 01349 } 01350 } 01351 } 01352 if (f) 01353 ast_frfree(f); 01354 } /* end while */ 01355 } else 01356 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data); 01357 } else { 01358 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data); 01359 switch(cause) { 01360 case AST_CAUSE_BUSY: 01361 state = AST_CONTROL_BUSY; 01362 break; 01363 case AST_CAUSE_CONGESTION: 01364 state = AST_CONTROL_CONGESTION; 01365 break; 01366 } 01367 } 01368 01369 ast_indicate(caller, -1); 01370 if (chan && ready) { 01371 if (chan->_state == AST_STATE_UP) 01372 state = AST_CONTROL_ANSWER; 01373 res = 0; 01374 } else if(chan) { 01375 res = -1; 01376 ast_hangup(chan); 01377 chan = NULL; 01378 } else { 01379 res = -1; 01380 } 01381 01382 if (outstate) 01383 *outstate = state; 01384 01385 if (chan && res <= 0) { 01386 if (chan->cdr || (chan->cdr = ast_cdr_alloc())) { 01387 char tmp[256]; 01388 ast_cdr_init(chan->cdr, chan); 01389 snprintf(tmp, 256, "%s/%s", type, (char *)data); 01390 ast_cdr_setapp(chan->cdr,"Dial",tmp); 01391 ast_cdr_update(chan); 01392 ast_cdr_start(chan->cdr); 01393 ast_cdr_end(chan->cdr); 01394 /* If the cause wasn't handled properly */ 01395 if (ast_cdr_disposition(chan->cdr,chan->hangupcause)) 01396 ast_cdr_failed(chan->cdr); 01397 } else { 01398 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n"); 01399 } 01400 } 01401 01402 return chan; 01403 }
struct ast_channel* ast_get_holded_call | ( | char * | uniqueid | ) | [read] |
Definition at line 2180 of file res_features.c.
References ast_get_channel_by_uniqueid_locked(), ast_log(), ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_verbose(), free, LOG_WARNING, holdeduser::next, option_verbose, holdeduser::uniqueid, and VERBOSE_PREFIX_3.
Referenced by ast_retrieve_call(), and ast_retrieve_call_to_death().
02181 { 02182 int res=-1; 02183 struct ast_channel *peer=NULL; 02184 struct holdeduser *pu, *pl=NULL; 02185 02186 ast_mutex_lock(&holding_lock); 02187 pu = holdlist; 02188 while(pu) { 02189 if (!strncmp(uniqueid,pu->uniqueid,sizeof(pu->uniqueid))) { 02190 if (pl) 02191 pl->next = pu->next; 02192 else 02193 holdlist = pu->next; 02194 break; 02195 } 02196 pl = pu; 02197 pu = pu->next; 02198 } 02199 ast_mutex_unlock(&holding_lock); 02200 if (pu) { 02201 peer = ast_get_channel_by_uniqueid_locked(pu->uniqueid); 02202 free(pu); 02203 if (peer) { 02204 res=0; 02205 if (option_verbose > 2) 02206 ast_verbose(VERBOSE_PREFIX_3 "Channel %s removed from hold.\n", peer->name); 02207 ast_moh_stop(peer); 02208 return peer; 02209 } else { 02210 if (option_verbose > 2) 02211 ast_verbose(VERBOSE_PREFIX_3 "Could not find channel with uniqueid %s.\n", uniqueid); 02212 return NULL; 02213 } 02214 } else { 02215 ast_log(LOG_WARNING, "Could not find held channel with uniqueid %s to retrieve.\n", uniqueid); 02216 } 02217 return NULL; 02218 }
int ast_hold_call | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer | |||
) |
Definition at line 2038 of file res_features.c.
References ast_channel::appl, ast_log(), ast_moh_start(), ast_mutex_lock(), ast_mutex_unlock(), holdeduser::chan, ast_channel::data, EVENT_FLAG_CALL, LOG_WARNING, malloc, manager_event(), holdeduser::next, holdeduser::start, holdeduser::uniqueid, and holdeduser::uniqueidpeer.
Referenced by ast_masq_hold_call().
02039 { 02040 /* We put the user in the parking list, then wake up the parking thread to be sure it looks 02041 after these channels too */ 02042 struct holdeduser *pu; 02043 pu = malloc(sizeof(struct holdeduser)); 02044 if (pu) { 02045 memset(pu, 0, sizeof(pu)); 02046 ast_mutex_lock(&holding_lock); 02047 chan->appl = "Holded Call"; 02048 chan->data = NULL; 02049 02050 pu->chan = chan; 02051 strncpy(pu->uniqueid, chan->uniqueid, sizeof(pu->uniqueid)); 02052 strncpy(pu->uniqueidpeer, peer->uniqueid, sizeof(pu->uniqueidpeer)); 02053 /* Start music on hold */ 02054 ast_moh_start(pu->chan, NULL, NULL); 02055 gettimeofday(&pu->start, NULL); 02056 pu->next = holdlist; 02057 holdlist = pu; 02058 ast_mutex_unlock(&holding_lock); 02059 /* Wake up the (presumably select()ing) thread */ 02060 pthread_kill(holding_thread, SIGURG); 02061 02062 manager_event(EVENT_FLAG_CALL, "HoldedCall", 02063 "Channel1: %s\r\n" 02064 "Channel2: %s\r\n" 02065 "Uniqueid1: %s\r\n" 02066 "Uniqueid2: %s\r\n" 02067 ,pu->chan->name, peer->name, pu->chan->uniqueid, peer->uniqueid); 02068 02069 } else { 02070 ast_log(LOG_WARNING, "Out of memory\n"); 02071 return -1; 02072 } 02073 return 0; 02074 }
static AST_LIST_HEAD_STATIC | ( | feature_list | , | |
ast_call_feature | ||||
) | [static] |
int ast_masq_autoanswer_login | ( | struct ast_channel * | rchan, | |
void * | data | |||
) |
Definition at line 2530 of file res_features.c.
References ast_autoanswer_login(), ast_channel_alloc(), ast_channel_masquerade(), ast_frfree, ast_log(), ast_read(), AST_STATE_DOWN, ast_string_field_build, ast_channel::context, ast_channel::exten, f, LOG_WARNING, name, ast_channel::priority, ast_channel::readformat, and ast_channel::writeformat.
Referenced by autoanswer_login_exec().
02531 { 02532 struct ast_channel *chan; 02533 struct ast_frame *f; 02534 /* Make a new, fake channel that we'll use to masquerade in the real one */ 02535 chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Autoanswer/%s", rchan->name); 02536 if (chan) { 02537 /* Let us keep track of the channel name */ 02538 ast_string_field_build(chan, name, "Autoanswer/%s",rchan->name); 02539 /* Make formats okay */ 02540 chan->readformat = rchan->readformat; 02541 chan->writeformat = rchan->writeformat; 02542 ast_channel_masquerade(chan, rchan); 02543 /* Setup the extensions and such */ 02544 strncpy(chan->context, rchan->context, sizeof(chan->context) - 1); 02545 strncpy(chan->exten, rchan->exten, sizeof(chan->exten) - 1); 02546 chan->priority = rchan->priority; 02547 /* might be dirty but we want trackable channels */ 02548 ast_string_field_build(chan, uniqueid, "%s",rchan->uniqueid); 02549 /* Make the masq execute */ 02550 f = ast_read(chan); 02551 if (f) 02552 ast_frfree(f); 02553 ast_autoanswer_login(chan, data); 02554 } else { 02555 ast_log(LOG_WARNING, "Unable to create aa channel\n"); 02556 return -1; 02557 } 02558 return 0; 02559 }
int ast_masq_hold_call | ( | struct ast_channel * | rchan, | |
struct ast_channel * | peer | |||
) |
Definition at line 2076 of file res_features.c.
References ast_channel_alloc(), ast_channel_masquerade(), ast_frfree, ast_hold_call(), ast_log(), ast_read(), AST_STATE_DOWN, ast_string_field_build, ast_channel::context, ast_channel::exten, f, LOG_WARNING, name, ast_channel::priority, ast_channel::readformat, and ast_channel::writeformat.
02077 { 02078 struct ast_channel *chan; 02079 struct ast_frame *f; 02080 /* Make a new, fake channel that we'll use to masquerade in the real one */ 02081 chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Onhold/%s",rchan->name); 02082 if (chan) { 02083 /* Let us keep track of the channel name */ 02084 ast_string_field_build(chan, name, "Onhold/%s",rchan->name); 02085 /* Make formats okay */ 02086 chan->readformat = rchan->readformat; 02087 chan->writeformat = rchan->writeformat; 02088 ast_channel_masquerade(chan, rchan); 02089 /* Setup the extensions and such */ 02090 strncpy(chan->context, rchan->context, sizeof(chan->context) - 1); 02091 strncpy(chan->exten, rchan->exten, sizeof(chan->exten) - 1); 02092 chan->priority = rchan->priority; 02093 /* this might be dirty, but we need to preserve the uniqueid */ 02094 ast_string_field_build(chan, uniqueid, "%s",rchan->uniqueid); 02095 /* Make the masq execute */ 02096 f = ast_read(chan); 02097 if (f) 02098 ast_frfree(f); 02099 ast_hold_call(chan, peer); 02100 return -1; 02101 } else { 02102 ast_log(LOG_WARNING, "Unable to create holded channel\n"); 02103 return -1; 02104 } 02105 return 0; 02106 }
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 512 of file res_features.c.
References ast_channel::amaflags, ast_channel_alloc(), ast_channel_masquerade(), ast_frfree, ast_log(), ast_park_call(), ast_read(), AST_STATE_DOWN, ast_channel::context, ast_channel::exten, f, LOG_WARNING, ast_channel::priority, ast_channel::readformat, set_c_e_p(), and ast_channel::writeformat.
Referenced by manager_park(), mgcp_ss(), parkandannounce_exec(), rpt_exec(), and ss_thread().
00513 { 00514 struct ast_channel *chan; 00515 struct ast_frame *f; 00516 00517 /* Make a new, fake channel that we'll use to masquerade in the real one */ 00518 if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) { 00519 ast_log(LOG_WARNING, "Unable to create parked channel\n"); 00520 return -1; 00521 } 00522 00523 /* Make formats okay */ 00524 chan->readformat = rchan->readformat; 00525 chan->writeformat = rchan->writeformat; 00526 ast_channel_masquerade(chan, rchan); 00527 00528 /* Setup the extensions and such */ 00529 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority); 00530 00531 /* Make the masq execute */ 00532 f = ast_read(chan); 00533 if (f) 00534 ast_frfree(f); 00535 00536 ast_park_call(chan, peer, timeout, extout); 00537 return 0; 00538 }
AST_MODULE_INFO | ( | ASTERISK_GPL_KEY | , | |
AST_MODFLAG_GLOBAL_SYMBOLS | , | |||
"Call Features Resource" | , | |||
. | load = load_module , |
|||
. | unload = unload_module , |
|||
. | reload = reload | |||
) |
AST_MUTEX_DEFINE_STATIC | ( | holding_lock | ) |
AST_MUTEX_DEFINE_STATIC | ( | parking_lock | ) |
protects all static variables above
AST_MUTEX_DEFINE_STATIC | ( | autoanswer_lock | ) |
int ast_park_call | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
int | timeout, | |||
int * | extout | |||
) |
Park a call.
Park a call and read back parked location.
Definition at line 507 of file res_features.c.
References park_call_full().
Referenced by ast_masq_park_call(), builtin_blindtransfer(), builtin_parkcall(), iax_park_thread(), and sip_park_thread().
00508 { 00509 return park_call_full(chan, peer, timeout, extout, NULL); 00510 }
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 214 of file res_features.c.
Referenced by builtin_blindtransfer(), dp_lookup(), handle_request_refer(), load_config(), mgcp_ss(), socket_process(), and ss_thread().
00215 { 00216 return parking_ext; 00217 }
int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
Definition at line 2918 of file res_features.c.
References ast_channel::_state, ast_answer(), ast_channel_masquerade(), ast_channel_unlock, ast_channel_walk_locked(), AST_CONTROL_ANSWER, ast_log(), ast_queue_control(), AST_STATE_RING, AST_STATE_RINGING, ast_channel::callgroup, LOG_DEBUG, LOG_WARNING, option_debug, ast_channel::pbx, and ast_channel::pickupgroup.
Referenced by cb_events(), handle_request_invite(), mgcp_ss(), and ss_thread().
02919 { 02920 struct ast_channel *cur = NULL; 02921 int res = -1; 02922 02923 while ( (cur = ast_channel_walk_locked(cur)) != NULL) { 02924 if (!cur->pbx && 02925 (cur != chan) && 02926 (chan->pickupgroup & cur->callgroup) && 02927 ((cur->_state == AST_STATE_RINGING) || 02928 (cur->_state == AST_STATE_RING))) { 02929 break; 02930 } 02931 ast_channel_unlock(cur); 02932 } 02933 if (cur) { 02934 if (option_debug) 02935 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name); 02936 res = ast_answer(chan); 02937 if (res) 02938 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); 02939 res = ast_queue_control(chan, AST_CONTROL_ANSWER); 02940 if (res) 02941 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); 02942 res = ast_channel_masquerade(cur, chan); 02943 if (res) 02944 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */ 02945 ast_channel_unlock(cur); 02946 } else { 02947 if (option_debug) 02948 ast_log(LOG_DEBUG, "No call pickup possible...\n"); 02949 } 02950 return res; 02951 }
char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 219 of file res_features.c.
Referenced by cb_events(), get_destination(), handle_request_invite(), handle_showfeatures(), mgcp_ss(), and ss_thread().
00220 { 00221 return pickup_ext; 00222 }
void ast_register_feature | ( | struct ast_call_feature * | feature | ) |
register new feature into feature_list
register new feature into feature_set
Definition at line 975 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().
00976 { 00977 if (!feature) { 00978 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 00979 return; 00980 } 00981 00982 AST_LIST_LOCK(&feature_list); 00983 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry); 00984 AST_LIST_UNLOCK(&feature_list); 00985 00986 if (option_verbose >= 2) 00987 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname); 00988 }
int ast_retrieve_call | ( | struct ast_channel * | chan, | |
char * | uniqueid | |||
) |
Definition at line 2108 of file res_features.c.
References ast_channel::_state, ast_answer(), ast_bridge_call(), ast_channel_make_compatible(), AST_FEATURE_REDIRECT, ast_get_holded_call(), ast_hangup(), ast_log(), ast_moh_stop(), ast_mutex_unlock(), AST_PBX_NO_HANGUP_PEER, ast_set_flag, AST_STATE_UP, ast_streamfile(), ast_verbose(), ast_waitstream(), ast_bridge_config::features_callee, ast_bridge_config::features_caller, LOG_WARNING, option_verbose, ast_bridge_config::play_warning, ast_bridge_config::timelimit, VERBOSE_PREFIX_3, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.
Referenced by retrieve_call_exec().
02109 { 02110 int res=-1, dres=-1; 02111 struct ast_channel *peer=NULL; 02112 struct ast_bridge_config config; 02113 02114 peer = ast_get_holded_call(uniqueid); 02115 02116 /* JK02: it helps to answer the channel if not already up */ 02117 if (chan->_state != AST_STATE_UP) { 02118 ast_answer(chan); 02119 } 02120 02121 if (peer) { 02122 ast_mutex_unlock(&peer->lock); 02123 ast_moh_stop(peer); 02124 res = ast_channel_make_compatible(chan, peer); 02125 if (res < 0) { 02126 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); 02127 ast_hangup(peer); 02128 return -1; 02129 } 02130 /* This runs sorta backwards, since we give the incoming channel control, as if it 02131 were the person called. */ 02132 if (option_verbose > 2) 02133 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to holded call %s\n", chan->name, peer->name); 02134 02135 memset(&config,0,sizeof(struct ast_bridge_config)); 02136 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 02137 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 02138 config.timelimit = 0; 02139 config.play_warning = 0; 02140 config.warning_freq = 0; 02141 config.warning_sound=NULL; 02142 res = ast_bridge_call(chan,peer,&config); 02143 02144 /* Simulate the PBX hanging up */ 02145 if (res != AST_PBX_NO_HANGUP_PEER) 02146 ast_hangup(peer); 02147 return res; 02148 } else { 02149 /* XXX Play a message XXX */ 02150 dres = ast_streamfile(chan, "pbx-invalidpark", chan->language); 02151 if (!dres) 02152 dres = ast_waitstream(chan, ""); 02153 else { 02154 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name); 02155 dres = 0; 02156 } 02157 } 02158 return res; 02159 }
int ast_retrieve_call_to_death | ( | char * | uniqueid | ) |
Definition at line 2161 of file res_features.c.
References ast_get_holded_call(), ast_hangup(), ast_log(), ast_mutex_unlock(), ast_verbose(), ast_channel::lock, LOG_WARNING, option_verbose, and VERBOSE_PREFIX_3.
02162 { 02163 int res=-1; 02164 struct ast_channel *peer=NULL; 02165 02166 peer = ast_get_holded_call(uniqueid); 02167 02168 if (peer) { 02169 res=0; 02170 if (option_verbose > 2) 02171 ast_verbose(VERBOSE_PREFIX_3 "Channel %s removed from hold.\n", peer->name); 02172 ast_mutex_unlock(&peer->lock); 02173 ast_hangup(peer); 02174 } else { 02175 ast_log(LOG_WARNING, "Could not find channel with uniqueid %s to retrieve.\n", uniqueid); 02176 } 02177 return res; 02178 }
AST_RWLOCK_DEFINE_STATIC | ( | features_lock | ) |
void ast_unregister_feature | ( | struct ast_call_feature * | feature | ) |
unregister feature from feature_list
unregister feature from feature_set
Definition at line 991 of file res_features.c.
References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free.
00992 { 00993 if (!feature) 00994 return; 00995 00996 AST_LIST_LOCK(&feature_list); 00997 AST_LIST_REMOVE(&feature_list,feature,feature_entry); 00998 AST_LIST_UNLOCK(&feature_list); 00999 free(feature); 01000 }
static void ast_unregister_features | ( | void | ) | [static] |
Remove all features in the list.
Definition at line 1003 of file res_features.c.
References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and free.
Referenced by load_config().
01004 { 01005 struct ast_call_feature *feature; 01006 01007 AST_LIST_LOCK(&feature_list); 01008 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry))) 01009 free(feature); 01010 AST_LIST_UNLOCK(&feature_list); 01011 }
static int autoanswer_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 2803 of file res_features.c.
References ast_channel::_state, ast_answer(), ast_autoanswer_login(), ast_bridge_call(), ast_channel_make_compatible(), AST_FEATURE_REDIRECT, ast_hangup(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_set_flag, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_verbose(), ast_waitstream(), aauser::chan, aauser::context, EVENT_FLAG_CALL, aauser::exten, ast_bridge_config::features_callee, ast_bridge_config::features_caller, free, LOG_WARNING, manager_event(), aauser::next, option_verbose, ast_bridge_config::play_warning, s, strsep(), ast_bridge_config::timelimit, VERBOSE_PREFIX_3, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.
Referenced by load_module().
02804 { 02805 int res=0; 02806 struct ast_channel *peer=NULL; 02807 struct aauser *pu, *pl=NULL; 02808 struct ast_bridge_config config; 02809 char *s, *stringp, *aacontext, *aaexten = NULL; 02810 char datastring[80]; 02811 struct ast_module_user *u; 02812 02813 02814 if (!data) { 02815 ast_log(LOG_WARNING, "Autoanswer requires an argument (extension number)\n"); 02816 return -1; 02817 } 02818 s = ast_strdupa((void *) data); 02819 stringp=s; 02820 aacontext = strsep(&stringp, "|"); 02821 aaexten = strsep(&stringp, "|"); 02822 if (!aaexten) { 02823 aaexten = aacontext; 02824 aacontext = NULL; 02825 } 02826 if (!aaexten) { 02827 ast_log(LOG_WARNING, "AutoanswerLogin requires at least an extension!\n"); 02828 return -1; 02829 } else { 02830 if (!aacontext) { 02831 aacontext = "default"; 02832 } 02833 } 02834 02835 u = ast_module_user_add(chan); 02836 ast_mutex_lock(&autoanswer_lock); 02837 pu = aalot; 02838 while(pu) { 02839 if ((!strncasecmp(pu->exten, aaexten, sizeof(pu->exten)-1)) && (!strncasecmp(pu->context, aacontext, sizeof(pu->context)-1))){ 02840 if (pl) 02841 pl->next = pu->next; 02842 else 02843 aalot = pu->next; 02844 break; 02845 } 02846 pl = pu; 02847 pu = pu->next; 02848 } 02849 ast_mutex_unlock(&autoanswer_lock); 02850 if (pu) { 02851 peer = pu->chan; 02852 free(pu); 02853 pu = NULL; 02854 } 02855 /* JK02: it helps to answer the channel if not already up */ 02856 if (chan->_state != AST_STATE_UP) { 02857 ast_answer(chan); 02858 } 02859 02860 if (peer) { 02861 ast_moh_stop(peer); 02862 /* Play a courtesy beep in the callED channel to prefix the bridge connecting */ 02863 if (!ast_strlen_zero(courtesytone)) { 02864 if (!ast_streamfile(peer, courtesytone, peer->language)) { 02865 if (ast_waitstream(peer, "") < 0) { 02866 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 02867 ast_hangup(peer); 02868 return -1; 02869 } 02870 } 02871 } 02872 02873 res = ast_channel_make_compatible(chan, peer); 02874 if (res < 0) { 02875 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); 02876 ast_hangup(peer); 02877 return -1; 02878 } 02879 /* This runs sorta backwards, since we give the incoming channel control, as if it 02880 were the person called. */ 02881 if (option_verbose > 2) 02882 ast_verbose(VERBOSE_PREFIX_3 "Channel %s autoanswered %s\n", peer->name, chan->name); 02883 manager_event(EVENT_FLAG_CALL, "Autoanswer", 02884 "Channel: %s\r\n" 02885 "Uniqueid: %s\r\n" 02886 "Channel2: %s\r\n" 02887 "Uniqueid2: %s\r\n" 02888 "Context: %s\r\n" 02889 "Exten: %s\r\n" 02890 ,chan->name, chan->uniqueid, peer->name, peer->uniqueid, aacontext, aaexten); 02891 02892 02893 memset(&config,0,sizeof(struct ast_bridge_config)); 02894 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 02895 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 02896 config.timelimit = 0; 02897 config.play_warning = 0; 02898 config.warning_freq = 0; 02899 config.warning_sound=NULL; 02900 res = ast_bridge_call(chan,peer,&config); 02901 02902 if (option_verbose > 2) 02903 ast_verbose(VERBOSE_PREFIX_3 "returning from bridge %s\n", peer->name); 02904 /* relogin */ 02905 snprintf(datastring, sizeof(datastring) - 1, "%s|%s", aacontext, aaexten); 02906 ast_autoanswer_login(peer, datastring); 02907 return res; 02908 } else { 02909 if (option_verbose > 2) 02910 ast_verbose(VERBOSE_PREFIX_3 "Nobody logged in for autoanswer %s@%s\n", aaexten, aacontext); 02911 res = -1; 02912 } 02913 ast_module_user_remove(u); 02914 return res; 02915 }
static int autoanswer_login_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 2561 of file res_features.c.
References ast_log(), ast_masq_autoanswer_login(), ast_module_user_add, ast_module_user_remove, and LOG_WARNING.
Referenced by load_module().
02562 { 02563 int res=0; 02564 struct ast_module_user *u; 02565 02566 u = ast_module_user_add(chan); 02567 if (!data) { 02568 ast_log(LOG_WARNING, "AutoanswerLogin requires an argument (extension number)\n"); 02569 return -1; 02570 } 02571 res = ast_masq_autoanswer_login(chan, data); 02572 ast_module_user_remove(u); 02573 return res; 02574 }
static void autoanswer_reregister_extensions | ( | void | ) | [static] |
Definition at line 2678 of file res_features.c.
References ast_add_extension2(), ast_context_create(), ast_context_find(), ast_log(), AST_MAX_EXTENSION, ast_mutex_lock(), ast_mutex_unlock(), aauser::context, aauser::exten, exten, free, LOG_ERROR, aauser::next, and strdup.
Referenced by reload().
02679 { 02680 struct aauser *cur; 02681 struct ast_context *con; 02682 char exten[AST_MAX_EXTENSION]; 02683 char args[AST_MAX_EXTENSION]; 02684 02685 ast_mutex_lock(&autoanswer_lock); 02686 02687 cur=aalot; 02688 while(cur) { 02689 con = ast_context_find(cur->context); 02690 if (!con) { 02691 con = ast_context_create(NULL,cur->context, registrar); 02692 if (!con) { 02693 ast_log(LOG_ERROR, "Context '%s' does not exist and unable to create\n", cur->context); 02694 } 02695 } 02696 if (con) { 02697 snprintf(exten, sizeof(exten), "%s", cur->exten); 02698 snprintf(args, sizeof(args), "%s|%s", cur->context, cur->exten); 02699 ast_add_extension2(con, 1, exten, 1, NULL, NULL, autoanswer, strdup((char *)args), free, registrar); 02700 } 02701 cur = cur->next; 02702 } 02703 02704 ast_mutex_unlock(&autoanswer_lock); 02705 }
static int builtin_atxfer | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
Definition at line 816 of file res_features.c.
References ast_channel::_softhangup, ast_channel::_state, ast_app_dtget(), ast_autoservice_start(), ast_autoservice_stop(), ast_best_codec(), ast_bridge_call(), ast_bridge_call_thread_launch(), ast_calloc, ast_channel_alloc(), ast_channel_masquerade(), ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, AST_DIGIT_ANY, ast_exists_extension(), ast_explicit_goto(), AST_FEATURE_DISCONNECT, ast_feature_request_and_dial(), AST_FLAGS_ALL, ast_frfree, ast_hangup(), ast_indicate(), ast_log(), ast_read(), ast_set_flag, AST_STATE_DOWN, AST_STATE_UP, ast_stream_and_wait(), ast_waitfordigit(), ast_bridge_thread_obj::bconfig, ast_bridge_thread_obj::chan, check_compat(), ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::context, ast_channel::exten, f, FEATURE_RETURN_SUCCESS, ast_bridge_config::features_callee, ast_bridge_config::features_caller, finishup(), LOG_DEBUG, LOG_WARNING, ast_channel::nativeformats, option_debug, ast_bridge_thread_obj::peer, ast_channel::priority, ast_channel::readformat, real_ctx(), set_peers(), and ast_channel::writeformat.
00817 { 00818 struct ast_channel *transferer; 00819 struct ast_channel *transferee; 00820 const char *transferer_real_context; 00821 char xferto[256] = ""; 00822 int res; 00823 int outstate=0; 00824 struct ast_channel *newchan; 00825 struct ast_channel *xferchan; 00826 struct ast_bridge_thread_obj *tobj; 00827 struct ast_bridge_config bconfig; 00828 struct ast_frame *f; 00829 int l; 00830 00831 if (option_debug) 00832 ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense); 00833 set_peers(&transferer, &transferee, peer, chan, sense); 00834 transferer_real_context = real_ctx(transferer, transferee); 00835 /* Start autoservice on chan while we talk to the originator */ 00836 ast_autoservice_start(transferee); 00837 ast_indicate(transferee, AST_CONTROL_HOLD); 00838 00839 /* Transfer */ 00840 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY); 00841 if (res < 0) { 00842 finishup(transferee); 00843 return res; 00844 } 00845 if (res > 0) /* If they've typed a digit already, handle it */ 00846 xferto[0] = (char) res; 00847 00848 /* this is specific of atxfer */ 00849 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 00850 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */ 00851 finishup(transferee); 00852 return res; 00853 } 00854 if (res == 0) { 00855 ast_log(LOG_WARNING, "Did not read data.\n"); 00856 finishup(transferee); 00857 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, "")) 00858 return -1; 00859 return FEATURE_RETURN_SUCCESS; 00860 } 00861 00862 /* valid extension, res == 1 */ 00863 if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) { 00864 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context); 00865 finishup(transferee); 00866 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, "")) 00867 return -1; 00868 return FEATURE_RETURN_SUCCESS; 00869 } 00870 00871 l = strlen(xferto); 00872 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); /* append context */ 00873 newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats), 00874 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name); 00875 ast_indicate(transferer, -1); 00876 if (!newchan) { 00877 finishup(transferee); 00878 /* any reason besides user requested cancel and busy triggers the failed sound */ 00879 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY && 00880 ast_stream_and_wait(transferer, xferfailsound, transferer->language, "")) 00881 return -1; 00882 return FEATURE_RETURN_SUCCESS; 00883 } 00884 00885 if (check_compat(transferer, newchan)) { 00886 /* we do mean transferee here, NOT transferer */ 00887 finishup(transferee); 00888 return -1; 00889 } 00890 memset(&bconfig,0,sizeof(struct ast_bridge_config)); 00891 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 00892 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 00893 res = ast_bridge_call(transferer, newchan, &bconfig); 00894 if (newchan->_softhangup || !transferer->_softhangup) { 00895 ast_hangup(newchan); 00896 if (ast_stream_and_wait(transferer, xfersound, transferer->language, "")) 00897 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 00898 finishup(transferee); 00899 transferer->_softhangup = 0; 00900 return FEATURE_RETURN_SUCCESS; 00901 } 00902 00903 if (check_compat(transferee, newchan)) { 00904 finishup(transferee); 00905 return -1; 00906 } 00907 00908 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00909 00910 if ((ast_autoservice_stop(transferee) < 0) 00911 || (ast_waitfordigit(transferee, 100) < 0) 00912 || (ast_waitfordigit(newchan, 100) < 0) 00913 || ast_check_hangup(transferee) 00914 || ast_check_hangup(newchan)) { 00915 ast_hangup(newchan); 00916 return -1; 00917 } 00918 00919 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name); 00920 if (!xferchan) { 00921 ast_hangup(newchan); 00922 return -1; 00923 } 00924 /* Make formats okay */ 00925 xferchan->readformat = transferee->readformat; 00926 xferchan->writeformat = transferee->writeformat; 00927 ast_channel_masquerade(xferchan, transferee); 00928 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority); 00929 xferchan->_state = AST_STATE_UP; 00930 ast_clear_flag(xferchan, AST_FLAGS_ALL); 00931 xferchan->_softhangup = 0; 00932 00933 if ((f = ast_read(xferchan))) 00934 ast_frfree(f); 00935 00936 newchan->_state = AST_STATE_UP; 00937 ast_clear_flag(newchan, AST_FLAGS_ALL); 00938 newchan->_softhangup = 0; 00939 00940 tobj = ast_calloc(1, sizeof(struct ast_bridge_thread_obj)); 00941 if (!tobj) { 00942 ast_hangup(xferchan); 00943 ast_hangup(newchan); 00944 return -1; 00945 } 00946 tobj->chan = xferchan; 00947 tobj->peer = newchan; 00948 tobj->bconfig = *config; 00949 00950 if (ast_stream_and_wait(newchan, xfersound, newchan->language, "")) 00951 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 00952 ast_bridge_call_thread_launch(tobj); 00953 return -1; /* XXX meaning the channel is bridged ? */ 00954 }
static int builtin_automonitor | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
Definition at line 602 of file res_features.c.
References ast_autoservice_start(), ast_autoservice_stop(), ast_log(), ast_monitor_stop(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_verbose(), ast_channel::cid, ast_callerid::cid_num, FEATURE_RETURN_SUCCESS, len, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_channel::monitor, option_verbose, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), S_OR, set_peers(), and VERBOSE_PREFIX_3.
00603 { 00604 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 00605 int x = 0; 00606 size_t len; 00607 struct ast_channel *caller_chan, *callee_chan; 00608 00609 if (!monitor_ok) { 00610 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 00611 return -1; 00612 } 00613 00614 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) { 00615 monitor_ok = 0; 00616 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 00617 return -1; 00618 } 00619 00620 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 00621 00622 if (!ast_strlen_zero(courtesytone)) { 00623 if (ast_autoservice_start(callee_chan)) 00624 return -1; 00625 if (ast_stream_and_wait(caller_chan, courtesytone, caller_chan->language, "")) { 00626 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 00627 ast_autoservice_stop(callee_chan); 00628 return -1; 00629 } 00630 if (ast_autoservice_stop(callee_chan)) 00631 return -1; 00632 } 00633 00634 if (callee_chan->monitor) { 00635 if (option_verbose > 3) 00636 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code); 00637 ast_monitor_stop(callee_chan, 1); 00638 return FEATURE_RETURN_SUCCESS; 00639 } 00640 00641 if (caller_chan && callee_chan) { 00642 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT"); 00643 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR"); 00644 00645 if (!touch_format) 00646 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT"); 00647 00648 if (!touch_monitor) 00649 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR"); 00650 00651 if (touch_monitor) { 00652 len = strlen(touch_monitor) + 50; 00653 args = alloca(len); 00654 touch_filename = alloca(len); 00655 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor); 00656 snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename); 00657 } else { 00658 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name)); 00659 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name)); 00660 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 00661 args = alloca(len); 00662 touch_filename = alloca(len); 00663 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id); 00664 snprintf(args, len, "%s|%s|m", S_OR(touch_format, "wav"), touch_filename); 00665 } 00666 00667 for( x = 0; x < strlen(args); x++) { 00668 if (args[x] == '/') 00669 args[x] = '-'; 00670 } 00671 00672 if (option_verbose > 3) 00673 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args); 00674 00675 pbx_exec(callee_chan, monitor_app, args); 00676 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 00677 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 00678 00679 return FEATURE_RETURN_SUCCESS; 00680 } 00681 00682 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); 00683 return -1; 00684 }
static int builtin_blindtransfer | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
Definition at line 713 of file res_features.c.
References ast_app_dtget(), ast_async_goto(), ast_autoservice_start(), ast_cdr_alloc(), ast_cdr_init(), ast_cdr_setapp(), ast_cdr_setdestchan(), ast_cdr_start(), AST_CONTROL_HOLD, AST_DIGIT_ANY, ast_exists_extension(), ast_indicate(), ast_log(), ast_park_call(), ast_parking_ext(), AST_PBX_KEEPALIVE, AST_PBX_NO_HANGUP_PEER, ast_stopstream(), ast_stream_and_wait(), ast_verbose(), ast_channel::cdr, check_goto_on_transfer(), ast_channel::cid, ast_callerid::cid_num, FEATURE_RETURN_SUCCESS, finishup(), LOG_WARNING, option_verbose, ast_channel::pbx, pbx_builtin_setvar_helper(), real_ctx(), set_c_e_p(), set_peers(), VERBOSE_PREFIX_2, and VERBOSE_PREFIX_3.
00714 { 00715 struct ast_channel *transferer; 00716 struct ast_channel *transferee; 00717 const char *transferer_real_context; 00718 char xferto[256]; 00719 int res; 00720 00721 set_peers(&transferer, &transferee, peer, chan, sense); 00722 transferer_real_context = real_ctx(transferer, transferee); 00723 /* Start autoservice on chan while we talk to the originator */ 00724 ast_autoservice_start(transferee); 00725 ast_indicate(transferee, AST_CONTROL_HOLD); 00726 00727 memset(xferto, 0, sizeof(xferto)); 00728 00729 /* Transfer */ 00730 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY); 00731 if (res < 0) { 00732 finishup(transferee); 00733 return -1; /* error ? */ 00734 } 00735 if (res > 0) /* If they've typed a digit already, handle it */ 00736 xferto[0] = (char) res; 00737 00738 ast_stopstream(transferer); 00739 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 00740 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */ 00741 finishup(transferee); 00742 return res; 00743 } 00744 if (!strcmp(xferto, ast_parking_ext())) { 00745 res = finishup(transferee); 00746 if (res) 00747 res = -1; 00748 else if (!ast_park_call(transferee, transferer, 0, NULL)) { /* success */ 00749 /* We return non-zero, but tell the PBX not to hang the channel when 00750 the thread dies -- We have to be careful now though. We are responsible for 00751 hanging up the channel, else it will never be hung up! */ 00752 00753 return (transferer == peer) ? AST_PBX_KEEPALIVE : AST_PBX_NO_HANGUP_PEER; 00754 } else { 00755 ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name); 00756 } 00757 /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */ 00758 } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) { 00759 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", transferee->name); 00760 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name); 00761 res=finishup(transferee); 00762 if (!transferer->cdr) { 00763 transferer->cdr=ast_cdr_alloc(); 00764 if (transferer) { 00765 ast_cdr_init(transferer->cdr, transferer); /* initilize our channel's cdr */ 00766 ast_cdr_start(transferer->cdr); 00767 } 00768 } 00769 if (transferer->cdr) { 00770 ast_cdr_setdestchan(transferer->cdr, transferee->name); 00771 ast_cdr_setapp(transferer->cdr, "BLINDTRANSFER",""); 00772 } 00773 if (!transferee->pbx) { 00774 /* Doh! Use our handy async_goto functions */ 00775 if (option_verbose > 2) 00776 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n" 00777 ,transferee->name, xferto, transferer_real_context); 00778 if (ast_async_goto(transferee, transferer_real_context, xferto, 1)) 00779 ast_log(LOG_WARNING, "Async goto failed :-(\n"); 00780 res = -1; 00781 } else { 00782 /* Set the channel's new extension, since it exists, using transferer context */ 00783 set_c_e_p(transferee, transferer_real_context, xferto, 0); 00784 } 00785 check_goto_on_transfer(transferer); 00786 return res; 00787 } else { 00788 if (option_verbose > 2) 00789 ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context); 00790 } 00791 if (ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0 ) { 00792 finishup(transferee); 00793 return -1; 00794 } 00795 ast_stopstream(transferer); 00796 res = finishup(transferee); 00797 if (res) { 00798 if (option_verbose > 1) 00799 ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name); 00800 return res; 00801 } 00802 return FEATURE_RETURN_SUCCESS; 00803 }
static int builtin_disconnect | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
Definition at line 686 of file res_features.c.
References ast_verbose(), FEATURE_RETURN_HANGUP, option_verbose, and VERBOSE_PREFIX_3.
00687 { 00688 if (option_verbose > 3) 00689 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code); 00690 return FEATURE_RETURN_HANGUP; 00691 }
static int builtin_parkcall | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
support routing for one touch call parking
Definition at line 569 of file res_features.c.
References ast_channel::_state, ast_answer(), ast_module_user_add, ast_module_user_remove, ast_park_call(), AST_PBX_KEEPALIVE, AST_PBX_NO_HANGUP_PEER, ast_safe_sleep(), AST_STATE_UP, ast_channel::exten, FEATURE_SENSE_CHAN, ast_channel::priority, and set_peers().
00570 { 00571 struct ast_channel *parker; 00572 struct ast_channel *parkee; 00573 int res = 0; 00574 struct ast_module_user *u; 00575 00576 u = ast_module_user_add(chan); 00577 00578 set_peers(&parker, &parkee, peer, chan, sense); 00579 /* Setup the exten/priority to be s/1 since we don't know 00580 where this call should return */ 00581 strcpy(chan->exten, "s"); 00582 chan->priority = 1; 00583 if (chan->_state != AST_STATE_UP) 00584 res = ast_answer(chan); 00585 if (!res) 00586 res = ast_safe_sleep(chan, 1000); 00587 if (!res) 00588 res = ast_park_call(parkee, parker, 0, NULL); 00589 00590 ast_module_user_remove(u); 00591 00592 if (!res) { 00593 if (sense == FEATURE_SENSE_CHAN) 00594 res = AST_PBX_NO_HANGUP_PEER; 00595 else 00596 res = AST_PBX_KEEPALIVE; 00597 } 00598 return res; 00599 00600 }
static int check_compat | ( | struct ast_channel * | c, | |
struct ast_channel * | newchan | |||
) | [static] |
Definition at line 805 of file res_features.c.
References ast_channel_make_compatible(), ast_hangup(), ast_log(), and LOG_WARNING.
Referenced by builtin_atxfer().
00806 { 00807 if (ast_channel_make_compatible(c, newchan) < 0) { 00808 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", 00809 c->name, newchan->name); 00810 ast_hangup(newchan); 00811 return -1; 00812 } 00813 return 0; 00814 }
static void check_goto_on_transfer | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 241 of file res_features.c.
References ast_channel::_softhangup, ast_channel::_state, ast_channel_alloc(), ast_channel_masquerade(), ast_clear_flag, AST_FLAGS_ALL, ast_frfree, ast_hangup(), ast_parseable_goto(), ast_pbx_start(), ast_read(), AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), f, pbx_builtin_getvar_helper(), ast_channel::readformat, and ast_channel::writeformat.
Referenced by builtin_blindtransfer().
00242 { 00243 struct ast_channel *xferchan; 00244 const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR"); 00245 char *x, *goto_on_transfer; 00246 struct ast_frame *f; 00247 00248 if (ast_strlen_zero(val)) 00249 return; 00250 00251 goto_on_transfer = ast_strdupa(val); 00252 00253 if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, chan->name))) 00254 return; 00255 00256 for (x = goto_on_transfer; x && *x; x++) { 00257 if (*x == '^') 00258 *x = '|'; 00259 } 00260 /* Make formats okay */ 00261 xferchan->readformat = chan->readformat; 00262 xferchan->writeformat = chan->writeformat; 00263 ast_channel_masquerade(xferchan, chan); 00264 ast_parseable_goto(xferchan, goto_on_transfer); 00265 xferchan->_state = AST_STATE_UP; 00266 ast_clear_flag(xferchan, AST_FLAGS_ALL); 00267 xferchan->_softhangup = 0; 00268 if ((f = ast_read(xferchan))) { 00269 ast_frfree(f); 00270 f = NULL; 00271 ast_pbx_start(xferchan); 00272 } else { 00273 ast_hangup(xferchan); 00274 } 00275 }
static void* do_autoanswer_thread | ( | void * | ignore | ) | [static] |
Definition at line 2706 of file res_features.c.
References ast_clear_flag, ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_HANGUP, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, ast_frfree, ast_hangup(), ast_log(), AST_MAX_EXTENSION, AST_MAX_FDS, ast_mutex_lock(), ast_mutex_unlock(), ast_read(), ast_select(), ast_set_flag, ast_verbose(), aauser::chan, aauser::context, EVENT_FLAG_CALL, aauser::exten, exten, f, ast_channel::fdno, ast_channel::fds, ast_frame::frametype, free, LOG_WARNING, manager_event(), aauser::next, option_verbose, aauser::start, ast_frame::subclass, and VERBOSE_PREFIX_2.
Referenced by load_module().
02707 { 02708 int ms, tms, max; 02709 struct ast_context *con; 02710 char exten[AST_MAX_EXTENSION]; 02711 struct aauser *pu, *pl, *pt = NULL; 02712 struct timeval tv; 02713 struct ast_frame *f; 02714 int x; 02715 fd_set rfds, efds; 02716 fd_set nrfds, nefds; 02717 FD_ZERO(&rfds); 02718 FD_ZERO(&efds); 02719 for (;;) { 02720 ms = -1; 02721 max = -1; 02722 ast_mutex_lock(&autoanswer_lock); 02723 pl = NULL; 02724 pu = aalot; 02725 gettimeofday(&tv, NULL); 02726 FD_ZERO(&nrfds); 02727 FD_ZERO(&nefds); 02728 while(pu) { 02729 tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000; 02730 for (x=0;x<AST_MAX_FDS;x++) { 02731 if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) { 02732 if (FD_ISSET(pu->chan->fds[x], &efds)) 02733 ast_set_flag(pu->chan, AST_FLAG_EXCEPTION); 02734 else 02735 ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION); 02736 pu->chan->fdno = x; 02737 /* See if they need servicing */ 02738 f = ast_read(pu->chan); 02739 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) { 02740 /* There's a problem, hang them up*/ 02741 if (option_verbose > 1) 02742 ast_verbose(VERBOSE_PREFIX_2 "%s logged out of autoanswer app\n", pu->chan->name); 02743 manager_event(EVENT_FLAG_CALL, "AutoanswerLogout", 02744 "Channel: %s\r\n" 02745 "Uniqueid: %s\r\n" 02746 "Context: %s\r\n" 02747 "Exten: %s\r\n" 02748 ,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten); 02749 ast_hangup(pu->chan); 02750 con = ast_context_find(pu->context); 02751 if (con) { 02752 snprintf(exten, sizeof(exten), "%s", pu->exten); 02753 if (ast_context_remove_extension2(con, exten, 1, registrar)) 02754 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 02755 } else { 02756 ast_log(LOG_WARNING, "Whoa, no %s context?\n", pu->exten); 02757 } 02758 /* And take them out of the parking lot */ 02759 if (pl) 02760 pl->next = pu->next; 02761 else 02762 aalot = pu->next; 02763 pt = pu; 02764 pu = pu->next; 02765 free(pt); 02766 break; 02767 } else { 02768 /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ 02769 ast_frfree(f); 02770 goto std; /* XXX Ick: jumping into an else statement??? XXX */ 02771 } 02772 } 02773 } 02774 if (x >= AST_MAX_FDS) { 02775 std: for (x=0;x<AST_MAX_FDS;x++) { 02776 /* Keep this one for next one */ 02777 if (pu->chan->fds[x] > -1) { 02778 FD_SET(pu->chan->fds[x], &nrfds); 02779 FD_SET(pu->chan->fds[x], &nefds); 02780 if (pu->chan->fds[x] > max) 02781 max = pu->chan->fds[x]; 02782 } 02783 } 02784 /* Keep track of our longest wait */ 02785 if ((tms < ms) || (ms < 0)) 02786 ms = tms; 02787 pl = pu; 02788 pu = pu->next; 02789 } 02790 } 02791 ast_mutex_unlock(&autoanswer_lock); 02792 rfds = nrfds; 02793 efds = nefds; 02794 tv.tv_sec = ms / 1000; 02795 tv.tv_usec = (ms % 1000) * 1000; 02796 /* Wait for something to happen */ 02797 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL); 02798 pthread_testcancel(); 02799 } 02800 return NULL; /* Never reached */ 02801 }
static void* do_holding_thread | ( | void * | ignore | ) | [static] |
Definition at line 2221 of file res_features.c.
References ast_clear_flag, AST_CONTROL_HANGUP, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, ast_frfree, ast_hangup(), AST_MAX_FDS, ast_mutex_lock(), ast_mutex_unlock(), ast_read(), ast_select(), ast_set_flag, ast_verbose(), holdeduser::chan, f, ast_channel::fdno, ast_channel::fds, ast_frame::frametype, free, holdeduser::next, option_verbose, holdeduser::start, ast_frame::subclass, and VERBOSE_PREFIX_2.
Referenced by load_module().
02222 { 02223 int ms, tms, max; 02224 struct holdeduser *pu, *pl, *pt = NULL; 02225 struct timeval tv; 02226 struct ast_frame *f; 02227 int x; 02228 fd_set rfds, efds; 02229 fd_set nrfds, nefds; 02230 FD_ZERO(&rfds); 02231 FD_ZERO(&efds); 02232 for (;;) { 02233 ms = -1; 02234 max = -1; 02235 ast_mutex_lock(&holding_lock); 02236 pl = NULL; 02237 pu = holdlist; 02238 gettimeofday(&tv, NULL); 02239 FD_ZERO(&nrfds); 02240 FD_ZERO(&nefds); 02241 while(pu) { 02242 tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000; 02243 for (x=0;x<AST_MAX_FDS;x++) { 02244 if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) { 02245 if (FD_ISSET(pu->chan->fds[x], &efds)) 02246 ast_set_flag(pu->chan, AST_FLAG_EXCEPTION); 02247 else 02248 ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION); 02249 pu->chan->fdno = x; 02250 /* See if they need servicing */ 02251 f = ast_read(pu->chan); 02252 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) { 02253 /* There's a problem, hang them up*/ 02254 if (option_verbose > 1) 02255 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being onhold\n", pu->chan->name); 02256 ast_hangup(pu->chan); 02257 /* find the corresponding channel and hang them up too! */ 02258 /* but only if it is not bridged yet! */ 02259 /* And take them out of the parking lot */ 02260 if (pl) 02261 pl->next = pu->next; 02262 else 02263 holdlist = pu->next; 02264 pt = pu; 02265 pu = pu->next; 02266 free(pt); 02267 break; 02268 } else { 02269 /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ 02270 ast_frfree(f); 02271 goto std; /* XXX Ick: jumping into an else statement??? XXX */ 02272 } 02273 } 02274 } 02275 if (x >= AST_MAX_FDS) { 02276 std: for (x=0;x<AST_MAX_FDS;x++) { 02277 /* Keep this one for next one */ 02278 if (pu->chan->fds[x] > -1) { 02279 FD_SET(pu->chan->fds[x], &nrfds); 02280 FD_SET(pu->chan->fds[x], &nefds); 02281 if (pu->chan->fds[x] > max) 02282 max = pu->chan->fds[x]; 02283 } 02284 } 02285 /* Keep track of our longest wait */ 02286 if ((tms < ms) || (ms < 0)) 02287 ms = tms; 02288 pl = pu; 02289 pu = pu->next; 02290 } 02291 } 02292 ast_mutex_unlock(&holding_lock); 02293 rfds = nrfds; 02294 efds = nefds; 02295 tv.tv_sec = ms / 1000; 02296 tv.tv_usec = (ms % 1000) * 1000; 02297 /* Wait for something to happen */ 02298 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL); 02299 pthread_testcancel(); 02300 } 02301 return NULL; /* Never reached */ 02302 }
static void* do_parking_thread | ( | void * | ignore | ) | [static] |
Take care of parked calls and unpark them if needed.
Definition at line 1703 of file res_features.c.
References ast_add_extension2(), ast_clear_flag, ast_context_create(), ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, ast_free, ast_frfree, ast_hangup(), ast_indicate(), ast_indicate_data(), ast_log(), AST_MAX_EXTENSION, AST_MAX_FDS, ast_mutex_lock(), ast_mutex_unlock(), ast_pbx_start(), ast_read(), ast_select(), ast_set_flag, ast_strdupa, ast_strlen_zero(), ast_verbose(), parkeduser::chan, ast_channel::context, parkeduser::context, ast_channel::exten, parkeduser::exten, f, ast_channel::fdno, ast_channel::fds, ast_frame::frametype, free, ast_channel::generatordata, LOG_DEBUG, LOG_ERROR, LOG_WARNING, parkeduser::moh_trys, parkeduser::next, notify_metermaids(), parkeduser::notquiteyet, option_debug, option_verbose, parkeduser::parkingexten, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, post_manager_event(), ast_channel::priority, parkeduser::priority, S_OR, set_c_e_p(), parkeduser::start, strdup, ast_frame::subclass, and VERBOSE_PREFIX_2.
Referenced by load_module().
01704 { 01705 fd_set rfds, efds; /* results from previous select, to be preserved across loops. */ 01706 FD_ZERO(&rfds); 01707 FD_ZERO(&efds); 01708 01709 for (;;) { 01710 struct parkeduser *pu, *pl, *pt = NULL; 01711 int ms = -1; /* select timeout, uninitialized */ 01712 int max = -1; /* max fd, none there yet */ 01713 fd_set nrfds, nefds; /* args for the next select */ 01714 FD_ZERO(&nrfds); 01715 FD_ZERO(&nefds); 01716 01717 ast_mutex_lock(&parking_lock); 01718 pl = NULL; 01719 pu = parkinglot; 01720 /* navigate the list with prev-cur pointers to support removals */ 01721 while (pu) { 01722 struct ast_channel *chan = pu->chan; /* shorthand */ 01723 int tms; /* timeout for this item */ 01724 int x; /* fd index in channel */ 01725 struct ast_context *con; 01726 01727 if (pu->notquiteyet) { /* Pretend this one isn't here yet */ 01728 pl = pu; 01729 pu = pu->next; 01730 continue; 01731 } 01732 tms = ast_tvdiff_ms(ast_tvnow(), pu->start); 01733 if (tms > pu->parkingtime) { 01734 ast_indicate(chan, AST_CONTROL_UNHOLD); 01735 /* Get chan, exten from derived kludge */ 01736 if (pu->peername[0]) { 01737 char *peername = ast_strdupa(pu->peername); 01738 char *cp = strrchr(peername, '-'); 01739 if (cp) 01740 *cp = 0; 01741 con = ast_context_find(parking_con_dial); 01742 if (!con) { 01743 con = ast_context_create(NULL, parking_con_dial, registrar); 01744 if (!con) 01745 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial); 01746 } 01747 if (con) { 01748 char returnexten[AST_MAX_EXTENSION]; 01749 snprintf(returnexten, sizeof(returnexten), "%s||t", peername); 01750 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar); 01751 } 01752 set_c_e_p(chan, parking_con_dial, peername, 1); 01753 } else { 01754 /* They've been waiting too long, send them back to where they came. Theoretically they 01755 should have their original extensions and such, but we copy to be on the safe side */ 01756 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 01757 } 01758 01759 post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan); 01760 01761 if (option_verbose > 1) 01762 ast_verbose(VERBOSE_PREFIX_2 "Timeout for %s parked on %d. Returning to %s,%s,%d\n", chan->name, pu->parkingnum, chan->context, chan->exten, chan->priority); 01763 /* Start up the PBX, or hang them up */ 01764 if (ast_pbx_start(chan)) { 01765 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name); 01766 ast_hangup(chan); 01767 } 01768 /* And take them out of the parking lot */ 01769 if (pl) 01770 pl->next = pu->next; 01771 else 01772 parkinglot = pu->next; 01773 pt = pu; 01774 pu = pu->next; 01775 con = ast_context_find(parking_con); 01776 if (con) { 01777 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL)) 01778 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 01779 else 01780 notify_metermaids(pt->parkingexten, parking_con); 01781 } else 01782 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 01783 free(pt); 01784 } else { /* still within parking time, process descriptors */ 01785 for (x = 0; x < AST_MAX_FDS; x++) { 01786 struct ast_frame *f; 01787 01788 if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds))) 01789 continue; /* nothing on this descriptor */ 01790 01791 if (FD_ISSET(chan->fds[x], &efds)) 01792 ast_set_flag(chan, AST_FLAG_EXCEPTION); 01793 else 01794 ast_clear_flag(chan, AST_FLAG_EXCEPTION); 01795 chan->fdno = x; 01796 01797 /* See if they need servicing */ 01798 f = ast_read(chan); 01799 if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP)) { 01800 if (f) 01801 ast_frfree(f); 01802 post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan); 01803 01804 /* There's a problem, hang them up*/ 01805 if (option_verbose > 1) 01806 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name); 01807 ast_hangup(chan); 01808 /* And take them out of the parking lot */ 01809 if (pl) 01810 pl->next = pu->next; 01811 else 01812 parkinglot = pu->next; 01813 pt = pu; 01814 pu = pu->next; 01815 con = ast_context_find(parking_con); 01816 if (con) { 01817 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL)) 01818 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 01819 else 01820 notify_metermaids(pt->parkingexten, parking_con); 01821 } else 01822 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 01823 free(pt); 01824 break; 01825 } else { 01826 /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ 01827 ast_frfree(f); 01828 if (pu->moh_trys < 3 && !chan->generatordata) { 01829 if (option_debug) 01830 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n"); 01831 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 01832 S_OR(parkmohclass, NULL), 01833 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 01834 pu->moh_trys++; 01835 } 01836 goto std; /*! \todo XXX Ick: jumping into an else statement??? XXX */ 01837 } 01838 01839 } /* end for */ 01840 if (x >= AST_MAX_FDS) { 01841 std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */ 01842 if (chan->fds[x] > -1) { 01843 FD_SET(chan->fds[x], &nrfds); 01844 FD_SET(chan->fds[x], &nefds); 01845 if (chan->fds[x] > max) 01846 max = chan->fds[x]; 01847 } 01848 } 01849 /* Keep track of our shortest wait */ 01850 if (tms < ms || ms < 0) 01851 ms = tms; 01852 pl = pu; 01853 pu = pu->next; 01854 } 01855 } 01856 } /* end while */ 01857 ast_mutex_unlock(&parking_lock); 01858 rfds = nrfds; 01859 efds = nefds; 01860 { 01861 struct timeval tv = ast_samp2tv(ms, 1000); 01862 /* Wait for something to happen */ 01863 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL); 01864 } 01865 pthread_testcancel(); 01866 } 01867 return NULL; /* Never reached */ 01868 }
static int feature_exec_app | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
exec an app by feature
Definition at line 1027 of file res_features.c.
References ast_call_feature::app, app, ast_call_feature::app_args, ast_autoservice_start(), ast_autoservice_stop(), AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_ONSELF, ast_log(), ast_moh_start(), ast_moh_stop(), AST_PBX_KEEPALIVE, AST_PBX_NO_HANGUP_PEER, ast_strlen_zero(), ast_test_flag, FEATURE_RETURN_KEEPTRYING, FEATURE_RETURN_NO_HANGUP_PEER, FEATURE_RETURN_PBX_KEEPALIVE, FEATURE_RETURN_SUCCESS, FEATURE_RETURN_SUCCESSBREAK, FEATURE_SENSE_CHAN, LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, pbx_exec(), and pbx_findapp().
Referenced by load_config().
01028 { 01029 struct ast_app *app; 01030 struct ast_call_feature *feature = data; 01031 struct ast_channel *work, *idle; 01032 int res; 01033 01034 if (!feature) { /* shouldn't ever happen! */ 01035 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n"); 01036 return -1; 01037 } 01038 01039 if (sense == FEATURE_SENSE_CHAN) { 01040 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 01041 return FEATURE_RETURN_KEEPTRYING; 01042 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 01043 work = chan; 01044 idle = peer; 01045 } else { 01046 work = peer; 01047 idle = chan; 01048 } 01049 } else { 01050 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 01051 return FEATURE_RETURN_KEEPTRYING; 01052 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 01053 work = peer; 01054 idle = chan; 01055 } else { 01056 work = chan; 01057 idle = peer; 01058 } 01059 } 01060 01061 if (!(app = pbx_findapp(feature->app))) { 01062 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app); 01063 return -2; 01064 } 01065 01066 ast_autoservice_start(idle); 01067 01068 if (!ast_strlen_zero(feature->moh_class)) 01069 ast_moh_start(idle, feature->moh_class, NULL); 01070 01071 res = pbx_exec(work, app, feature->app_args); 01072 01073 if (!ast_strlen_zero(feature->moh_class)) 01074 ast_moh_stop(idle); 01075 01076 ast_autoservice_stop(idle); 01077 01078 if (res == AST_PBX_KEEPALIVE) 01079 return FEATURE_RETURN_PBX_KEEPALIVE; 01080 else if (res == AST_PBX_NO_HANGUP_PEER) 01081 return FEATURE_RETURN_NO_HANGUP_PEER; 01082 else if (res) 01083 return FEATURE_RETURN_SUCCESSBREAK; 01084 01085 return FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */ 01086 }
static struct ast_call_feature* find_dynamic_feature | ( | const char * | name | ) | [static, read] |
find a feature by name
Definition at line 1014 of file res_features.c.
References AST_LIST_TRAVERSE, and ast_call_feature::sname.
Referenced by ast_feature_interpret(), load_config(), and set_config_flags().
01015 { 01016 struct ast_call_feature *tmp; 01017 01018 AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) { 01019 if (!strcasecmp(tmp->sname, name)) 01020 break; 01021 } 01022 01023 return tmp; 01024 }
static int finishup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 693 of file res_features.c.
References ast_autoservice_stop(), AST_CONTROL_UNHOLD, and ast_indicate().
Referenced by builtin_atxfer(), and builtin_blindtransfer().
00694 { 00695 ast_indicate(chan, AST_CONTROL_UNHOLD); 00696 00697 return ast_autoservice_stop(chan); 00698 }
static int handle_autoanswer | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 2496 of file res_features.c.
References ast_cli(), ast_mutex_lock(), ast_mutex_unlock(), aauser::chan, aauser::context, aauser::exten, aauser::next, and RESULT_SUCCESS.
02497 { 02498 struct aauser *cur; 02499 02500 ast_cli(fd, "%25s %10s %15s \n", "Channel" 02501 , "Extension", "Context"); 02502 02503 ast_mutex_lock(&autoanswer_lock); 02504 02505 cur=aalot; 02506 while(cur) { 02507 ast_cli(fd, "%25s %10s %15s\n",cur->chan->name, cur->exten, cur->context); 02508 02509 cur = cur->next; 02510 } 02511 02512 ast_mutex_unlock(&autoanswer_lock); 02513 02514 return RESULT_SUCCESS; 02515 }
static int handle_parkedcalls | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 2355 of file res_features.c.
References ast_cli(), ast_mutex_lock(), ast_mutex_unlock(), parkeduser::chan, parkeduser::context, parkeduser::exten, parkeduser::next, parkeduser::parkingexten, parkeduser::parkingtime, parkeduser::priority, RESULT_SUCCESS, and parkeduser::start.
02356 { 02357 struct parkeduser *cur; 02358 int numparked = 0; 02359 02360 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel" 02361 , "Context", "Extension", "Pri", "Timeout"); 02362 02363 ast_mutex_lock(&parking_lock); 02364 02365 for (cur = parkinglot; cur; cur = cur->next) { 02366 ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n" 02367 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten 02368 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)); 02369 02370 numparked++; 02371 } 02372 ast_mutex_unlock(&parking_lock); 02373 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : ""); 02374 02375 02376 return RESULT_SUCCESS; 02377 }
static int handle_showfeatures | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 2314 of file res_features.c.
References ast_cli(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_pickup_ext(), ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_call_feature::default_exten, ast_call_feature::exten, exten, FEATURES_COUNT, ast_call_feature::fname, format, RESULT_SUCCESS, and ast_call_feature::sname.
02315 { 02316 int i; 02317 struct ast_call_feature *feature; 02318 char format[] = "%-25s %-7s %-7s\n"; 02319 02320 ast_cli(fd, format, "Builtin Feature", "Default", "Current"); 02321 ast_cli(fd, format, "---------------", "-------", "-------"); 02322 02323 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */ 02324 02325 ast_rwlock_rdlock(&features_lock); 02326 for (i = 0; i < FEATURES_COUNT; i++) 02327 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten); 02328 ast_rwlock_unlock(&features_lock); 02329 02330 ast_cli(fd, "\n"); 02331 ast_cli(fd, format, "Dynamic Feature", "Default", "Current"); 02332 ast_cli(fd, format, "---------------", "-------", "-------"); 02333 if (AST_LIST_EMPTY(&feature_list)) 02334 ast_cli(fd, "(none)\n"); 02335 else { 02336 AST_LIST_LOCK(&feature_list); 02337 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) 02338 ast_cli(fd, format, feature->sname, "no def", feature->exten); 02339 AST_LIST_UNLOCK(&feature_list); 02340 } 02341 ast_cli(fd, "\nCall parking\n"); 02342 ast_cli(fd, "------------\n"); 02343 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext); 02344 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con); 02345 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop); 02346 ast_cli(fd,"\n"); 02347 02348 return RESULT_SUCCESS; 02349 }
static int load_config | ( | void | ) | [static] |
Definition at line 2968 of file res_features.c.
References ast_call_feature::app, app, ast_call_feature::app_args, ast_add_extension2(), ast_calloc, ast_config_destroy(), ast_config_load(), ast_context_create(), ast_context_find(), ast_context_remove_extension2(), AST_FEATURE_FLAG_BYBOTH, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_NEEDSDTMF, AST_FEATURE_FLAG_ONPEER, AST_FEATURE_FLAG_ONSELF, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), AST_MAX_EXTENSION, AST_MODULE_LOAD_DECLINE, ast_parking_ext(), ast_register_feature(), ast_set_flag, ast_strdupa, ast_strlen_zero(), ast_true(), ast_unregister_features(), ast_variable_browse(), ast_verbose(), DEFAULT_FEATURE_DIGIT_TIMEOUT, DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER, DEFAULT_PARK_TIME, DEFAULT_TRANSFER_DIGIT_TIMEOUT, ast_call_feature::exten, exten, FEATURE_APP_ARGS_LEN, FEATURE_APP_LEN, feature_exec_app(), FEATURE_EXTEN_LEN, FEATURE_MOH_LEN, FEATURE_SNAME_LEN, find_dynamic_feature(), ast_variable::lineno, LOG_DEBUG, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, ast_variable::name, ast_variable::next, notify_metermaids(), ast_call_feature::operation, option_debug, option_verbose, park_add_hints(), remap_feature(), ast_call_feature::sname, strsep(), unmap_features(), ast_variable::value, var, and VERBOSE_PREFIX_2.
02969 { 02970 int start = 0, end = 0; 02971 int res; 02972 struct ast_context *con = NULL; 02973 struct ast_config *cfg = NULL; 02974 struct ast_variable *var = NULL; 02975 char old_parking_ext[AST_MAX_EXTENSION]; 02976 char old_parking_con[AST_MAX_EXTENSION] = ""; 02977 02978 if (!ast_strlen_zero(parking_con)) { 02979 strcpy(old_parking_ext, parking_ext); 02980 strcpy(old_parking_con, parking_con); 02981 } 02982 02983 /* Reset to defaults */ 02984 strcpy(parking_con, "parkedcalls"); 02985 strcpy(parking_con_dial, "park-dial"); 02986 strcpy(parking_ext, "700"); 02987 strcpy(pickup_ext, "*8"); 02988 strcpy(parkmohclass, "default"); 02989 courtesytone[0] = '\0'; 02990 strcpy(xfersound, "beep"); 02991 strcpy(xferfailsound, "pbx-invalid"); 02992 parking_start = 701; 02993 parking_stop = 750; 02994 parkfindnext = 0; 02995 adsipark = 0; 02996 parkaddhints = 0; 02997 02998 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 02999 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 03000 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 03001 03002 cfg = ast_config_load("features.conf"); 03003 if (!cfg) { 03004 ast_log(LOG_WARNING,"Could not load features.conf\n"); 03005 return AST_MODULE_LOAD_DECLINE; 03006 } 03007 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { 03008 if (!strcasecmp(var->name, "parkext")) { 03009 ast_copy_string(parking_ext, var->value, sizeof(parking_ext)); 03010 } else if (!strcasecmp(var->name, "context")) { 03011 ast_copy_string(parking_con, var->value, sizeof(parking_con)); 03012 } else if (!strcasecmp(var->name, "parkingtime")) { 03013 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) { 03014 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value); 03015 parkingtime = DEFAULT_PARK_TIME; 03016 } else 03017 parkingtime = parkingtime * 1000; 03018 } else if (!strcasecmp(var->name, "parkpos")) { 03019 if (sscanf(var->value, "%d-%d", &start, &end) != 2) { 03020 ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers at line %d of features.conf\n", var->lineno); 03021 } else { 03022 parking_start = start; 03023 parking_stop = end; 03024 } 03025 } else if (!strcasecmp(var->name, "findslot")) { 03026 parkfindnext = (!strcasecmp(var->value, "next")); 03027 } else if (!strcasecmp(var->name, "parkinghints")) { 03028 parkaddhints = ast_true(var->value); 03029 } else if (!strcasecmp(var->name, "adsipark")) { 03030 adsipark = ast_true(var->value); 03031 } else if (!strcasecmp(var->name, "transferdigittimeout")) { 03032 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) { 03033 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value); 03034 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 03035 } else 03036 transferdigittimeout = transferdigittimeout * 1000; 03037 } else if (!strcasecmp(var->name, "featuredigittimeout")) { 03038 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) { 03039 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value); 03040 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 03041 } 03042 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) { 03043 if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) { 03044 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value); 03045 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 03046 } else 03047 atxfernoanswertimeout = atxfernoanswertimeout * 1000; 03048 } else if (!strcasecmp(var->name, "courtesytone")) { 03049 ast_copy_string(courtesytone, var->value, sizeof(courtesytone)); 03050 } else if (!strcasecmp(var->name, "parkedplay")) { 03051 if (!strcasecmp(var->value, "both")) 03052 parkedplay = 2; 03053 else if (!strcasecmp(var->value, "parked")) 03054 parkedplay = 1; 03055 else 03056 parkedplay = 0; 03057 } else if (!strcasecmp(var->name, "xfersound")) { 03058 ast_copy_string(xfersound, var->value, sizeof(xfersound)); 03059 } else if (!strcasecmp(var->name, "xferfailsound")) { 03060 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound)); 03061 } else if (!strcasecmp(var->name, "pickupexten")) { 03062 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext)); 03063 } else if (!strcasecmp(var->name, "parkedmusicclass")) { 03064 ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass)); 03065 } 03066 } 03067 03068 unmap_features(); 03069 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) { 03070 if (remap_feature(var->name, var->value)) 03071 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); 03072 } 03073 03074 /* Map a key combination to an application*/ 03075 ast_unregister_features(); 03076 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) { 03077 char *tmp_val = ast_strdupa(var->value); 03078 char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 03079 struct ast_call_feature *feature; 03080 03081 /* strsep() sets the argument to NULL if match not found, and it 03082 * is safe to use it with a NULL argument, so we don't check 03083 * between calls. 03084 */ 03085 exten = strsep(&tmp_val,","); 03086 activatedby = strsep(&tmp_val,","); 03087 app = strsep(&tmp_val,","); 03088 app_args = strsep(&tmp_val,","); 03089 moh_class = strsep(&tmp_val,","); 03090 03091 activateon = strsep(&activatedby, "/"); 03092 03093 /*! \todo XXX var_name or app_args ? */ 03094 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) { 03095 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n", 03096 app, exten, activateon, var->name); 03097 continue; 03098 } 03099 03100 AST_LIST_LOCK(&feature_list); 03101 if ((feature = find_dynamic_feature(var->name))) { 03102 AST_LIST_UNLOCK(&feature_list); 03103 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name); 03104 continue; 03105 } 03106 AST_LIST_UNLOCK(&feature_list); 03107 03108 if (!(feature = ast_calloc(1, sizeof(*feature)))) 03109 continue; 03110 03111 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN); 03112 ast_copy_string(feature->app, app, FEATURE_APP_LEN); 03113 ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN); 03114 03115 if (app_args) 03116 ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN); 03117 03118 if (moh_class) 03119 ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN); 03120 03121 ast_copy_string(feature->exten, exten, sizeof(feature->exten)); 03122 feature->operation = feature_exec_app; 03123 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF); 03124 03125 /* Allow caller and calle to be specified for backwards compatability */ 03126 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) 03127 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF); 03128 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) 03129 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER); 03130 else { 03131 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s'," 03132 " must be 'self', or 'peer'\n", var->name); 03133 continue; 03134 } 03135 03136 if (ast_strlen_zero(activatedby)) 03137 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 03138 else if (!strcasecmp(activatedby, "caller")) 03139 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER); 03140 else if (!strcasecmp(activatedby, "callee")) 03141 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE); 03142 else if (!strcasecmp(activatedby, "both")) 03143 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 03144 else { 03145 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s'," 03146 " must be 'caller', or 'callee', or 'both'\n", var->name); 03147 continue; 03148 } 03149 03150 ast_register_feature(feature); 03151 03152 if (option_verbose >= 1) 03153 ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten); 03154 } 03155 ast_config_destroy(cfg); 03156 03157 /* Remove the old parking extension */ 03158 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) { 03159 if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar)) 03160 notify_metermaids(old_parking_ext, old_parking_con); 03161 if (option_debug) 03162 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con); 03163 } 03164 03165 if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) { 03166 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); 03167 return -1; 03168 } 03169 res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar); 03170 if (parkaddhints) 03171 park_add_hints(parking_con, parking_start, parking_stop); 03172 if (!res) 03173 notify_metermaids(ast_parking_ext(), parking_con); 03174 return res; 03175 03176 }
static int load_module | ( | void | ) | [static] |
Definition at line 3184 of file res_features.c.
References ast_cli_register_multiple(), ast_devstate_prov_add(), ast_manager_register, ast_manager_register2(), ast_pthread_create, ast_register_application(), autoanswer_exec(), autoanswer_login_exec(), do_autoanswer_thread(), do_holding_thread(), do_parking_thread(), EVENT_FLAG_CALL, load_config(), manager_park(), manager_parking_status(), metermaidstate(), park_call_exec(), park_exec(), and retrieve_call_exec().
03185 { 03186 int res; 03187 03188 memset(parking_ext, 0, sizeof(parking_ext)); 03189 memset(parking_con, 0, sizeof(parking_con)); 03190 03191 if ((res = load_config())) 03192 return res; 03193 ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); 03194 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL); 03195 ast_pthread_create(&holding_thread, NULL, do_holding_thread, NULL); 03196 res = ast_register_application(parkedcall, park_exec, synopsis, descrip); 03197 if (!res) 03198 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2); 03199 if (!res) { 03200 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" ); 03201 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park, 03202 "Park a channel", mandescr_park); 03203 } 03204 03205 res |= ast_register_application(holdedcall, retrieve_call_exec, synopsis, descrip); 03206 ast_pthread_create(&autoanswer_thread, NULL, do_autoanswer_thread, NULL); 03207 if (!res) 03208 res |= ast_register_application(autoanswerlogin, autoanswer_login_exec, synopsis3, descrip3); 03209 if (!res) 03210 res |= ast_register_application(autoanswer, autoanswer_exec, synopsis4, descrip4); 03211 03212 res |= ast_devstate_prov_add("Park", metermaidstate); 03213 03214 return res; 03215 }
static int manager_park | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 2442 of file res_features.c.
References ast_channel_unlock, ast_get_channel_by_name_locked(), ast_masq_park_call(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_strlen_zero(), astman_get_header(), astman_send_ack(), and astman_send_error().
Referenced by load_module().
02443 { 02444 const char *channel = astman_get_header(m, "Channel"); 02445 const char *channel2 = astman_get_header(m, "Channel2"); 02446 const char *timeout = astman_get_header(m, "Timeout"); 02447 char buf[BUFSIZ]; 02448 int to = 0; 02449 int res = 0; 02450 int parkExt = 0; 02451 struct ast_channel *ch1, *ch2; 02452 02453 if (ast_strlen_zero(channel)) { 02454 astman_send_error(s, m, "Channel not specified"); 02455 return 0; 02456 } 02457 02458 if (ast_strlen_zero(channel2)) { 02459 astman_send_error(s, m, "Channel2 not specified"); 02460 return 0; 02461 } 02462 02463 ch1 = ast_get_channel_by_name_locked(channel); 02464 if (!ch1) { 02465 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel); 02466 astman_send_error(s, m, buf); 02467 return 0; 02468 } 02469 02470 ch2 = ast_get_channel_by_name_locked(channel2); 02471 if (!ch2) { 02472 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2); 02473 astman_send_error(s, m, buf); 02474 ast_channel_unlock(ch1); 02475 return 0; 02476 } 02477 02478 if (!ast_strlen_zero(timeout)) { 02479 sscanf(timeout, "%d", &to); 02480 } 02481 02482 res = ast_masq_park_call(ch1, ch2, to, &parkExt); 02483 if (!res) { 02484 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT); 02485 astman_send_ack(s, m, "Park successful"); 02486 } else { 02487 astman_send_error(s, m, "Park failure"); 02488 } 02489 02490 ast_channel_unlock(ch1); 02491 ast_channel_unlock(ch2); 02492 02493 return 0; 02494 }
static int manager_parking_status | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Dump lot status.
Definition at line 2394 of file res_features.c.
References ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, parkeduser::next, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, RESULT_SUCCESS, S_OR, and parkeduser::start.
Referenced by load_module().
02395 { 02396 struct parkeduser *cur; 02397 const char *id = astman_get_header(m, "ActionID"); 02398 char idText[256] = ""; 02399 02400 if (!ast_strlen_zero(id)) 02401 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 02402 02403 astman_send_ack(s, m, "Parked calls will follow"); 02404 02405 ast_mutex_lock(&parking_lock); 02406 02407 for (cur = parkinglot; cur; cur = cur->next) { 02408 astman_append(s, "Event: ParkedCall\r\n" 02409 "Exten: %d\r\n" 02410 "Channel: %s\r\n" 02411 "From: %s\r\n" 02412 "Timeout: %ld\r\n" 02413 "CallerID: %s\r\n" 02414 "CallerIDName: %s\r\n" 02415 "Unqiueid: %s\r\n\r\n" 02416 "%s" 02417 "\r\n", 02418 cur->parkingnum, cur->chan->name, cur->peername, 02419 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL), 02420 S_OR(cur->chan->cid.cid_num, ""), /* XXX in other places it is <unknown> */ 02421 S_OR(cur->chan->cid.cid_name, ""), cur->chan->uniqueid, 02422 idText); 02423 } 02424 02425 astman_append(s, 02426 "Event: ParkedCallsComplete\r\n" 02427 "%s" 02428 "\r\n",idText); 02429 02430 ast_mutex_unlock(&parking_lock); 02431 02432 return RESULT_SUCCESS; 02433 }
static int metermaidstate | ( | const char * | data | ) | [static] |
metermaids callback from devicestate.c
Definition at line 346 of file res_features.c.
References AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, ast_exists_extension(), ast_log(), ast_strdupa, context, exten, LOG_DEBUG, option_debug, and strsep().
Referenced by load_module().
00347 { 00348 int res = AST_DEVICE_INVALID; 00349 char *context = ast_strdupa(data); 00350 char *exten; 00351 00352 exten = strsep(&context, "@"); 00353 if (!context) 00354 return res; 00355 00356 if (option_debug > 3) 00357 ast_log(LOG_DEBUG, "Checking state of exten %s in context %s\n", exten, context); 00358 00359 res = ast_exists_extension(NULL, context, exten, 1, NULL); 00360 00361 if (!res) 00362 return AST_DEVICE_NOT_INUSE; 00363 else 00364 return AST_DEVICE_INUSE; 00365 }
static void notify_metermaids | ( | char * | exten, | |
char * | context | |||
) | [static] |
Notify metermaids that we've changed an extension.
Definition at line 335 of file res_features.c.
References ast_device_state_changed(), ast_log(), LOG_DEBUG, and option_debug.
Referenced by do_parking_thread(), load_config(), park_call_full(), and park_exec().
00336 { 00337 if (option_debug > 3) 00338 ast_log(LOG_DEBUG, "Notification of state change to metermaids %s@%s\n", exten, context); 00339 00340 /* Send notification to devicestate subsystem */ 00341 ast_device_state_changed("park:%s@%s", exten, context); 00342 return; 00343 }
static void park_add_hints | ( | char * | context, | |
int | start, | |||
int | stop | |||
) | [static] |
Add parking hints for all defined parking lots.
Definition at line 2954 of file res_features.c.
References ast_add_extension(), AST_MAX_EXTENSION, exten, and PRIORITY_HINT.
Referenced by load_config().
02955 { 02956 int numext; 02957 char device[AST_MAX_EXTENSION]; 02958 char exten[10]; 02959 02960 for (numext = start; numext <= stop; numext++) { 02961 snprintf(exten, sizeof(exten), "%d", numext); 02962 snprintf(device, sizeof(device), "park:%s@%s", exten, context); 02963 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar); 02964 } 02965 }
static int park_call_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Park a call.
Definition at line 1871 of file res_features.c.
References ast_channel::_state, ast_answer(), ast_module_user_add, ast_module_user_remove, AST_PBX_KEEPALIVE, ast_safe_sleep(), AST_STATE_UP, ast_strdupa, ast_channel::exten, park_call_full(), and ast_channel::priority.
Referenced by load_module().
01872 { 01873 /* Cache the original channel name in case we get masqueraded in the middle 01874 * of a park--it is still theoretically possible for a transfer to happen before 01875 * we get here, but it is _really_ unlikely */ 01876 char *orig_chan_name = ast_strdupa(chan->name); 01877 /* Data is unused at the moment but could contain a parking 01878 lot context eventually */ 01879 int res = 0; 01880 struct ast_module_user *u; 01881 01882 u = ast_module_user_add(chan); 01883 01884 /* Setup the exten/priority to be s/1 since we don't know 01885 where this call should return */ 01886 strcpy(chan->exten, "s"); 01887 chan->priority = 1; 01888 /* Answer if call is not up */ 01889 if (chan->_state != AST_STATE_UP) 01890 res = ast_answer(chan); 01891 /* Sleep to allow VoIP streams to settle down */ 01892 if (!res) 01893 res = ast_safe_sleep(chan, 1000); 01894 /* Park the call */ 01895 if (!res) 01896 res = park_call_full(chan, NULL, 0, NULL, orig_chan_name); 01897 01898 ast_module_user_remove(u); 01899 01900 return !res ? AST_PBX_KEEPALIVE : res; 01901 }
static int park_call_full | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
int | timeout, | |||
int * | extout, | |||
char * | orig_chan_name | |||
) | [static] |
Definition at line 367 of file res_features.c.
References adsi_announce_park(), ast_channel::appl, ast_add_extension2(), ast_adsi_available(), ast_adsi_unload_session(), ast_calloc, ast_clear_flag, ast_context_create(), ast_context_find(), AST_CONTROL_HOLD, ast_exists_extension(), AST_FLAG_MASQ_NOSTREAM, ast_free, ast_indicate_data(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_say_digits(), ast_set_flag, ast_strlen_zero(), ast_verbose(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::context, parkeduser::context, ast_channel::data, EVENT_FLAG_CALL, ast_channel::exten, parkeduser::exten, free, LOG_ERROR, LOG_WARNING, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, manager_event(), parkeduser::next, notify_metermaids(), parkeduser::notquiteyet, option_verbose, parkeduser::parkingexten, parkeduser::parkingnum, parkeduser::parkingtime, pbx_builtin_getvar_helper(), parkeduser::peername, ast_channel::priority, parkeduser::priority, S_OR, parkeduser::start, strdup, and VERBOSE_PREFIX_2.
Referenced by ast_park_call(), and park_call_exec().
00368 { 00369 struct parkeduser *pu, *cur; 00370 int i, x = -1, parking_range; 00371 struct ast_context *con; 00372 const char *parkingexten; 00373 00374 /* Allocate memory for parking data */ 00375 if (!(pu = ast_calloc(1, sizeof(*pu)))) 00376 return -1; 00377 00378 /* Lock parking lot */ 00379 ast_mutex_lock(&parking_lock); 00380 /* Check for channel variable PARKINGEXTEN */ 00381 parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN"); 00382 if (!ast_strlen_zero(parkingexten)) { 00383 if (ast_exists_extension(NULL, parking_con, parkingexten, 1, NULL)) { 00384 ast_mutex_unlock(&parking_lock); 00385 free(pu); 00386 ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con); 00387 return 0; /* Continue execution if possible */ 00388 } 00389 ast_copy_string(pu->parkingexten, parkingexten, sizeof(pu->parkingexten)); 00390 x = atoi(parkingexten); 00391 } else { 00392 /* Select parking space within range */ 00393 parking_range = parking_stop - parking_start+1; 00394 for (i = 0; i < parking_range; i++) { 00395 x = (i + parking_offset) % parking_range + parking_start; 00396 cur = parkinglot; 00397 while(cur) { 00398 if (cur->parkingnum == x) 00399 break; 00400 cur = cur->next; 00401 } 00402 if (!cur) 00403 break; 00404 } 00405 00406 if (!(i < parking_range)) { 00407 ast_log(LOG_WARNING, "No more parking spaces\n"); 00408 free(pu); 00409 ast_mutex_unlock(&parking_lock); 00410 return -1; 00411 } 00412 /* Set pointer for next parking */ 00413 if (parkfindnext) 00414 parking_offset = x - parking_start + 1; 00415 } 00416 00417 chan->appl = "Parked Call"; 00418 chan->data = NULL; 00419 00420 pu->chan = chan; 00421 00422 /* Put the parked channel on hold if we have two different channels */ 00423 if (chan != peer) { 00424 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 00425 S_OR(parkmohclass, NULL), 00426 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 00427 } 00428 00429 pu->start = ast_tvnow(); 00430 pu->parkingnum = x; 00431 pu->parkingtime = (timeout > 0) ? timeout : parkingtime; 00432 if (extout) 00433 *extout = x; 00434 00435 if (peer) 00436 ast_copy_string(pu->peername, peer->name, sizeof(pu->peername)); 00437 00438 /* Remember what had been dialed, so that if the parking 00439 expires, we try to come back to the same place */ 00440 ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context)); 00441 ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten)); 00442 pu->priority = chan->macropriority ? chan->macropriority : chan->priority; 00443 pu->next = parkinglot; 00444 parkinglot = pu; 00445 00446 /* If parking a channel directly, don't quiet yet get parking running on it */ 00447 if (peer == chan) 00448 pu->notquiteyet = 1; 00449 ast_mutex_unlock(&parking_lock); 00450 /* Wake up the (presumably select()ing) thread */ 00451 pthread_kill(parking_thread, SIGURG); 00452 if (option_verbose > 1) 00453 ast_verbose(VERBOSE_PREFIX_2 "Parked %s on %d@%s. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, parking_con, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000)); 00454 00455 if (pu->parkingnum != -1) 00456 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x); 00457 manager_event(EVENT_FLAG_CALL, "ParkedCall", 00458 "Exten: %s\r\n" 00459 "Channel: %s\r\n" 00460 "From: %s\r\n" 00461 "Timeout: %ld\r\n" 00462 "CallerID: %s\r\n" 00463 "CallerIDName: %s\r\n" 00464 "Uniqueid: %s\r\n", 00465 pu->parkingexten, pu->chan->name, peer ? peer->name : "", 00466 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL), 00467 S_OR(pu->chan->cid.cid_num, "<unknown>"), 00468 S_OR(pu->chan->cid.cid_name, "<unknown>"), 00469 pu->chan->uniqueid 00470 ); 00471 00472 if (peer && adsipark && ast_adsi_available(peer)) { 00473 adsi_announce_park(peer, pu->parkingexten); /* Only supports parking numbers */ 00474 ast_adsi_unload_session(peer); 00475 } 00476 00477 con = ast_context_find(parking_con); 00478 if (!con) 00479 con = ast_context_create(NULL, parking_con, registrar); 00480 if (!con) /* Still no context? Bad */ 00481 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); 00482 /* Tell the peer channel the number of the parking space */ 00483 if (peer && ((pu->parkingnum != -1 && ast_strlen_zero(orig_chan_name)) || !strcasecmp(peer->name, orig_chan_name))) { /* Only say number if it's a number and the channel hasn't been masqueraded away */ 00484 /* Make sure we don't start saying digits to the channel being parked */ 00485 ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM); 00486 ast_say_digits(peer, pu->parkingnum, "", peer->language); 00487 ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM); 00488 } 00489 if (con) { 00490 if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), ast_free, registrar)) 00491 notify_metermaids(pu->parkingexten, parking_con); 00492 } 00493 if (pu->notquiteyet) { 00494 /* Wake up parking thread if we're really done */ 00495 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 00496 S_OR(parkmohclass, NULL), 00497 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 00498 pu->notquiteyet = 0; 00499 pthread_kill(parking_thread, SIGURG); 00500 } 00501 return 0; 00502 }
static int park_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Pickup parked call.
Definition at line 1904 of file res_features.c.
References ast_channel::_state, ast_answer(), ast_bridge_call(), ast_cdr_setdestchan(), ast_channel_make_compatible(), ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_UNHOLD, AST_FEATURE_REDIRECT, ast_hangup(), ast_indicate(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_mutex_lock(), ast_mutex_unlock(), AST_PBX_NO_HANGUP_PEER, ast_set_flag, AST_STATE_UP, ast_stream_and_wait(), ast_streamfile(), ast_strlen_zero(), ast_verbose(), ast_waitstream(), ast_channel::cdr, parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, error(), EVENT_FLAG_CALL, ast_bridge_config::features_callee, ast_bridge_config::features_caller, free, LOG_WARNING, manager_event(), parkeduser::next, notify_metermaids(), option_verbose, parkeduser::parkingexten, parkeduser::parkingnum, pbx_builtin_setvar_helper(), S_OR, and VERBOSE_PREFIX_3.
Referenced by load_module().
01905 { 01906 int res = 0; 01907 struct ast_module_user *u; 01908 struct ast_channel *peer=NULL; 01909 struct parkeduser *pu, *pl=NULL; 01910 struct ast_context *con; 01911 01912 int park; 01913 struct ast_bridge_config config; 01914 01915 if (!data) { 01916 ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n"); 01917 return -1; 01918 } 01919 01920 u = ast_module_user_add(chan); 01921 01922 park = atoi((char *)data); 01923 ast_mutex_lock(&parking_lock); 01924 pu = parkinglot; 01925 while(pu) { 01926 if (pu->parkingnum == park) { 01927 if (pl) 01928 pl->next = pu->next; 01929 else 01930 parkinglot = pu->next; 01931 break; 01932 } 01933 pl = pu; 01934 pu = pu->next; 01935 } 01936 ast_mutex_unlock(&parking_lock); 01937 if (pu) { 01938 peer = pu->chan; 01939 con = ast_context_find(parking_con); 01940 if (con) { 01941 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL)) 01942 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 01943 else 01944 notify_metermaids(pu->parkingexten, parking_con); 01945 } else 01946 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 01947 01948 manager_event(EVENT_FLAG_CALL, "UnParkedCall", 01949 "Exten: %s\r\n" 01950 "Channel: %s\r\n" 01951 "From: %s\r\n" 01952 "CallerID: %s\r\n" 01953 "CallerIDName: %s\r\n" 01954 "Uniqueid: %s\r\n", 01955 pu->parkingexten, pu->chan->name, chan->name, 01956 S_OR(pu->chan->cid.cid_num, "<unknown>"), 01957 S_OR(pu->chan->cid.cid_name, "<unknown>"), 01958 pu->chan->uniqueid 01959 ); 01960 01961 free(pu); 01962 } 01963 /* JK02: it helps to answer the channel if not already up */ 01964 if (chan->_state != AST_STATE_UP) 01965 ast_answer(chan); 01966 01967 if (peer) { 01968 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */ 01969 01970 if (!ast_strlen_zero(courtesytone)) { 01971 int error = 0; 01972 ast_indicate(peer, AST_CONTROL_UNHOLD); 01973 if (parkedplay == 0) { 01974 error = ast_stream_and_wait(chan, courtesytone, chan->language, ""); 01975 } else if (parkedplay == 1) { 01976 error = ast_stream_and_wait(peer, courtesytone, chan->language, ""); 01977 } else if (parkedplay == 2) { 01978 if (!ast_streamfile(chan, courtesytone, chan->language) && 01979 !ast_streamfile(peer, courtesytone, chan->language)) { 01980 /*! \todo XXX we would like to wait on both! */ 01981 res = ast_waitstream(chan, ""); 01982 if (res >= 0) 01983 res = ast_waitstream(peer, ""); 01984 if (res < 0) 01985 error = 1; 01986 } 01987 } 01988 if (error) { 01989 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 01990 ast_hangup(peer); 01991 ast_module_user_remove(u); 01992 return -1; 01993 } 01994 } else 01995 ast_indicate(peer, AST_CONTROL_UNHOLD); 01996 01997 res = ast_channel_make_compatible(chan, peer); 01998 if (res < 0) { 01999 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); 02000 ast_hangup(peer); 02001 ast_module_user_remove(u); 02002 return -1; 02003 } 02004 /* This runs sorta backwards, since we give the incoming channel control, as if it 02005 were the person called. */ 02006 if (option_verbose > 2) 02007 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park); 02008 02009 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 02010 ast_cdr_setdestchan(chan->cdr, peer->name); 02011 memset(&config, 0, sizeof(struct ast_bridge_config)); 02012 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 02013 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 02014 res = ast_bridge_call(chan, peer, &config); 02015 02016 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 02017 ast_cdr_setdestchan(chan->cdr, peer->name); 02018 02019 /* Simulate the PBX hanging up */ 02020 if (res != AST_PBX_NO_HANGUP_PEER) 02021 ast_hangup(peer); 02022 ast_module_user_remove(u); 02023 return res; 02024 } else { 02025 /*! \todo XXX Play a message XXX */ 02026 if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, "")) 02027 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name); 02028 if (option_verbose > 2) 02029 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park); 02030 res = -1; 02031 } 02032 02033 ast_module_user_remove(u); 02034 02035 return res; 02036 }
static void post_manager_event | ( | const char * | s, | |
char * | parkingexten, | |||
struct ast_channel * | chan | |||
) | [static] |
Definition at line 1686 of file res_features.c.
References ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, EVENT_FLAG_CALL, manager_event(), and S_OR.
Referenced by do_parking_thread().
01687 { 01688 manager_event(EVENT_FLAG_CALL, s, 01689 "Exten: %s\r\n" 01690 "Channel: %s\r\n" 01691 "CallerID: %s\r\n" 01692 "CallerIDName: %s\r\n" 01693 "Uniqueid: %s\r\n\r\n", 01694 parkingexten, 01695 chan->name, 01696 S_OR(chan->cid.cid_num, "<unknown>"), 01697 S_OR(chan->cid.cid_name, "<unknown>"), 01698 chan->uniqueid 01699 ); 01700 }
static const char* real_ctx | ( | struct ast_channel * | transferer, | |
struct ast_channel * | transferee | |||
) | [static] |
Find the context for the transfer.
Definition at line 701 of file res_features.c.
References ast_strlen_zero(), ast_channel::context, ast_channel::macrocontext, pbx_builtin_getvar_helper(), and s.
Referenced by builtin_atxfer(), and builtin_blindtransfer().
00702 { 00703 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"); 00704 if (ast_strlen_zero(s)) 00705 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT"); 00706 if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */ 00707 s = transferer->macrocontext; 00708 if (ast_strlen_zero(s)) 00709 s = transferer->context; 00710 return s; 00711 }
static int reload | ( | void | ) | [static] |
Definition at line 3178 of file res_features.c.
References autoanswer_reregister_extensions(), and load_config().
03179 { 03180 autoanswer_reregister_extensions(); 03181 return load_config(); 03182 }
static int remap_feature | ( | const char * | name, | |
const char * | value | |||
) | [static] |
Definition at line 1098 of file res_features.c.
References ast_rwlock_unlock(), ast_rwlock_wrlock(), exten, and FEATURES_COUNT.
Referenced by load_config().
01099 { 01100 int x, res = -1; 01101 01102 ast_rwlock_wrlock(&features_lock); 01103 for (x = 0; x < FEATURES_COUNT; x++) { 01104 if (strcasecmp(builtin_features[x].sname, name)) 01105 continue; 01106 01107 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten)); 01108 res = 0; 01109 break; 01110 } 01111 ast_rwlock_unlock(&features_lock); 01112 01113 return res; 01114 }
static int retrieve_call_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 2304 of file res_features.c.
References ast_module_user_add, ast_module_user_remove, and ast_retrieve_call().
Referenced by load_module().
02304 { 02305 int res=0; 02306 struct ast_module_user *u; 02307 char *uniqueid = (char *)data; 02308 u = ast_module_user_add(chan); 02309 res = ast_retrieve_call(chan, uniqueid); 02310 ast_module_user_remove(u); 02311 return res; 02312 }
static void set_c_e_p | ( | struct ast_channel * | chan, | |
const char * | context, | |||
const char * | ext, | |||
int | pri | |||
) | [static] |
store context, priority and extension
Definition at line 234 of file res_features.c.
References ast_channel::context, ast_channel::exten, and ast_channel::priority.
Referenced by ast_masq_park_call(), builtin_blindtransfer(), and do_parking_thread().
00235 { 00236 ast_copy_string(chan->context, context, sizeof(chan->context)); 00237 ast_copy_string(chan->exten, ext, sizeof(chan->exten)); 00238 chan->priority = pri; 00239 }
static void set_config_flags | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config | |||
) | [static] |
Definition at line 1182 of file res_features.c.
References AST_BRIDGE_DTMF_CHANNEL_0, AST_BRIDGE_DTMF_CHANNEL_1, ast_clear_flag, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_NEEDSDTMF, AST_FLAGS_ALL, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_set_flag, ast_strdupa, ast_test_flag, ast_call_feature::feature_mask, ast_bridge_config::features_callee, ast_bridge_config::features_caller, FEATURES_COUNT, find_dynamic_feature(), pbx_builtin_getvar_helper(), and strsep().
Referenced by ast_bridge_call().
01183 { 01184 int x; 01185 01186 ast_clear_flag(config, AST_FLAGS_ALL); 01187 01188 ast_rwlock_rdlock(&features_lock); 01189 for (x = 0; x < FEATURES_COUNT; x++) { 01190 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) 01191 continue; 01192 01193 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask)) 01194 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 01195 01196 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask)) 01197 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 01198 } 01199 ast_rwlock_unlock(&features_lock); 01200 01201 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) { 01202 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"); 01203 01204 if (dynamic_features) { 01205 char *tmp = ast_strdupa(dynamic_features); 01206 char *tok; 01207 struct ast_call_feature *feature; 01208 01209 /* while we have a feature */ 01210 while ((tok = strsep(&tmp, "#"))) { 01211 AST_LIST_LOCK(&feature_list); 01212 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) { 01213 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 01214 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 01215 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 01216 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 01217 } 01218 AST_LIST_UNLOCK(&feature_list); 01219 } 01220 } 01221 } 01222 }
static void set_peers | ( | struct ast_channel ** | caller, | |
struct ast_channel ** | callee, | |||
struct ast_channel * | peer, | |||
struct ast_channel * | chan, | |||
int | sense | |||
) | [static] |
set caller and callee according to the direction
Definition at line 556 of file res_features.c.
References FEATURE_SENSE_PEER.
Referenced by builtin_atxfer(), builtin_automonitor(), builtin_blindtransfer(), and builtin_parkcall().
00558 { 00559 if (sense == FEATURE_SENSE_PEER) { 00560 *caller = peer; 00561 *callee = chan; 00562 } else { 00563 *callee = peer; 00564 *caller = chan; 00565 } 00566 }
static int unload_module | ( | void | ) | [static] |
Definition at line 3218 of file res_features.c.
References ast_cli_unregister_multiple(), ast_devstate_prov_del(), ast_manager_unregister(), ast_module_user_hangup_all, and ast_unregister_application().
03219 { 03220 ast_module_user_hangup_all(); 03221 03222 ast_manager_unregister("ParkedCalls"); 03223 ast_manager_unregister("Park"); 03224 ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); 03225 ast_unregister_application(parkcall); 03226 ast_unregister_application(autoanswer); 03227 ast_unregister_application(autoanswerlogin); 03228 ast_unregister_application(holdedcall); 03229 ast_devstate_prov_del("Park"); 03230 return ast_unregister_application(parkedcall); 03231 }
static void unmap_features | ( | void | ) | [static] |
Definition at line 1088 of file res_features.c.
References ast_rwlock_unlock(), ast_rwlock_wrlock(), exten, and FEATURES_COUNT.
Referenced by load_config().
01089 { 01090 int x; 01091 01092 ast_rwlock_wrlock(&features_lock); 01093 for (x = 0; x < FEATURES_COUNT; x++) 01094 strcpy(builtin_features[x].exten, builtin_features[x].default_exten); 01095 ast_rwlock_unlock(&features_lock); 01096 }
Definition at line 198 of file res_features.c.
int adsipark [static] |
Definition at line 104 of file res_features.c.
int atxfernoanswertimeout [static] |
Definition at line 109 of file res_features.c.
char* autoanswer = "Autoanswer" [static] |
Definition at line 144 of file res_features.c.
pthread_t autoanswer_thread [static] |
Definition at line 200 of file res_features.c.
char* autoanswerlogin = "AutoanswerLogin" [static] |
Definition at line 137 of file res_features.c.
struct ast_call_feature builtin_features[] [static] |
Definition at line 962 of file res_features.c.
struct ast_cli_entry cli_features[] [static] |
Definition at line 2517 of file res_features.c.
struct ast_cli_entry cli_show_features_deprecated [static] |
Initial value:
{ { "show", "features", NULL }, handle_showfeatures, NULL, NULL }
Definition at line 2383 of file res_features.c.
char courtesytone[256] [static] |
Courtesy tone
Definition at line 96 of file res_features.c.
char* descrip [static] |
Initial value:
"ParkedCall(exten):" "Used to connect to a parked call. This application is always\n" "registered internally and does not need to be explicitly added\n" "into the dialplan, although you should include the 'parkedcalls'\n" "context.\n"
Definition at line 116 of file res_features.c.
char* descrip2 [static] |
Definition at line 126 of file res_features.c.
char* descrip3 [static] |
Initial value:
"AutoanswerLogin([context]|exten):" "Used to login to the autoanswer application for an extension.\n"
Definition at line 141 of file res_features.c.
char* descrip4 [static] |
Initial value:
"Autoanswer([context]|exten):" "Used to autoanswer a call for an extension.\n"
Definition at line 148 of file res_features.c.
int featuredigittimeout [static] |
Definition at line 107 of file res_features.c.
char* holdedcall = "HoldedCall" [static] |
Definition at line 84 of file res_features.c.
pthread_t holding_thread [static] |
Definition at line 212 of file res_features.c.
struct holdeduser* holdlist [static] |
Definition at line 204 of file res_features.c.
char mandescr_park[] [static] |
Definition at line 2435 of file res_features.c.
struct ast_app* monitor_app = NULL [static] |
Definition at line 151 of file res_features.c.
int monitor_ok = 1 [static] |
Definition at line 152 of file res_features.c.
int parkaddhints = 0 [static] |
Add parking hints automatically
Definition at line 86 of file res_features.c.
char* parkcall = "Park" [static] |
Definition at line 122 of file res_features.c.
char* parkedcall = "ParkedCall" [static] |
Definition at line 83 of file res_features.c.
int parkedplay = 0 [static] |
Who to play the courtesy tone to
Definition at line 97 of file res_features.c.
int parkfindnext [static] |
Definition at line 102 of file res_features.c.
char parking_con[AST_MAX_EXTENSION] [static] |
Context for which parking is made accessible
Definition at line 88 of file res_features.c.
char parking_con_dial[AST_MAX_EXTENSION] [static] |
Context for dialback for parking (KLUDGE)
Definition at line 89 of file res_features.c.
char parking_ext[AST_MAX_EXTENSION] [static] |
Extension you type to park the call
Definition at line 90 of file res_features.c.
int parking_offset [static] |
Definition at line 101 of file res_features.c.
int parking_start [static] |
First available extension for parking
Definition at line 93 of file res_features.c.
int parking_stop [static] |
Last available extension for parking
Definition at line 94 of file res_features.c.
pthread_t parking_thread [static] |
Definition at line 210 of file res_features.c.
struct parkeduser* parkinglot [static] |
Definition at line 202 of file res_features.c.
int parkingtime = DEFAULT_PARK_TIME [static] |
No more than 45 seconds parked before you do something with them
Definition at line 87 of file res_features.c.
char parkmohclass[MAX_MUSICCLASS] [static] |
Music class used for parking
Definition at line 92 of file res_features.c.
char pickup_ext[AST_MAX_EXTENSION] [static] |
Call pickup extension
Definition at line 91 of file res_features.c.
char* registrar = "res_features" [static] |
Registrar for operations
Definition at line 111 of file res_features.c.
char showautoanswer_help[] [static] |
Initial value:
"Usage: show autoanswer\n" " Lists currently logged in autoanswer users.\n"
Definition at line 2388 of file res_features.c.
char showfeatures_help[] [static] |
Initial value:
"Usage: feature list\n" " Lists currently configured features.\n"
Definition at line 2351 of file res_features.c.
char showparked_help[] [static] |
Initial value:
"Usage: show parkedcalls\n" " Lists currently parked calls.\n"
Definition at line 2379 of file res_features.c.
char* synopsis = "Answer a parked call" [static] |
Definition at line 114 of file res_features.c.
char* synopsis2 = "Park yourself" [static] |
Definition at line 124 of file res_features.c.
char* synopsis3 = "Log in for autoanswer" [static] |
Definition at line 139 of file res_features.c.
char* synopsis4 = "Autoanswer a call" [static] |
Definition at line 146 of file res_features.c.
int transferdigittimeout [static] |
Definition at line 106 of file res_features.c.
char xferfailsound[256] [static] |
Call transfer failure sound
Definition at line 99 of file res_features.c.
char xfersound[256] [static] |
Call transfer sound
Definition at line 98 of file res_features.c.