#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) } |
enum | { BRIDGE_OPT_PLAYTONE = (1 << 0) } |
Functions | |
static int | action_bridge (struct mansession *s, const struct message *m) |
static int | adsi_announce_park (struct ast_channel *chan, char *parkingexten) |
AST_APP_OPTIONS (bridge_exec_options, BEGIN_OPTIONS END_OPTIONS) | |
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, const char *language) |
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 | bridge_exec (struct ast_channel *chan, void *data) |
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_bridge_masquerade (struct ast_channel *chan, struct ast_channel *tmpchan) |
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 char * | app_bridge = "Bridge" |
static int | atxfernoanswertimeout |
static char * | autoanswer = "Autoanswer" |
static pthread_t | autoanswer_thread |
static char * | autoanswerlogin = "AutoanswerLogin" |
static char * | bridge_descrip |
static char * | bridge_synopsis = "Bridge two channels" |
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_bridge [] |
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 76 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 578 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 575 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 577 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 580 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 989 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 78 of file res_features.c.
00078 { 00079 AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0), 00080 AST_FEATURE_FLAG_ONPEER = (1 << 1), 00081 AST_FEATURE_FLAG_ONSELF = (1 << 2), 00082 AST_FEATURE_FLAG_BYCALLEE = (1 << 3), 00083 AST_FEATURE_FLAG_BYCALLER = (1 << 4), 00084 AST_FEATURE_FLAG_BYBOTH = (3 << 3), 00085 };
anonymous enum |
Definition at line 3379 of file res_features.c.
03379 { 03380 BRIDGE_OPT_PLAYTONE = (1 << 0), 03381 };
static int action_bridge | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 2447 of file res_features.c.
References ast_channel::_state, ast_answer(), ast_bridge_call_thread_launch(), ast_calloc, ast_channel_alloc(), ast_channel_free(), ast_channel_make_compatible(), ast_get_channel_by_name_prefix_locked(), ast_hangup(), ast_log(), ast_mutex_unlock(), AST_STATE_DOWN, AST_STATE_UP, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_waitstream(), astman_get_header(), astman_send_ack(), astman_send_error(), ast_bridge_thread_obj::chan, do_bridge_masquerade(), errno, ast_channel::lock, LOG_WARNING, ast_bridge_thread_obj::peer, playtone(), and ast_bridge_thread_obj::return_to_pbx.
Referenced by load_module().
02448 { 02449 const char *channela = astman_get_header(m, "Channel1"); 02450 const char *channelb = astman_get_header(m, "Channel2"); 02451 const char *playtone = astman_get_header(m, "Tone"); 02452 struct ast_channel *chana = NULL, *chanb = NULL; 02453 struct ast_channel *tmpchana = NULL, *tmpchanb = NULL; 02454 struct ast_bridge_thread_obj *tobj = NULL; 02455 02456 /* make sure valid channels were specified */ 02457 if (!ast_strlen_zero(channela) && !ast_strlen_zero(channelb)) { 02458 chana = ast_get_channel_by_name_prefix_locked(channela, strlen(channela)); 02459 chanb = ast_get_channel_by_name_prefix_locked(channelb, strlen(channelb)); 02460 if (chana) 02461 ast_mutex_unlock(&chana->lock); 02462 if (chanb) 02463 ast_mutex_unlock(&chanb->lock); 02464 02465 /* send errors if any of the channels could not be found/locked */ 02466 if (!chana) { 02467 char buf[256]; 02468 snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela); 02469 astman_send_error(s, m, buf); 02470 return 0; 02471 } 02472 if (!chanb) { 02473 char buf[256]; 02474 snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb); 02475 astman_send_error(s, m, buf); 02476 return 0; 02477 } 02478 } else { 02479 astman_send_error(s, m, "Missing channel parameter in request"); 02480 return 0; 02481 } 02482 02483 /* Answer the channels if needed */ 02484 if (chana->_state != AST_STATE_UP) 02485 ast_answer(chana); 02486 if (chanb->_state != AST_STATE_UP) 02487 ast_answer(chanb); 02488 02489 /* create the placeholder channels and grab the other channels */ 02490 if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 02491 NULL, NULL, 0, "Bridge/%s", chana->name))) { 02492 astman_send_error(s, m, "Unable to create temporary channel!"); 02493 return 1; 02494 } 02495 02496 if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 02497 NULL, NULL, 0, "Bridge/%s", chanb->name))) { 02498 astman_send_error(s, m, "Unable to create temporary channels!"); 02499 ast_channel_free(tmpchana); 02500 return 1; 02501 } 02502 02503 do_bridge_masquerade(chana, tmpchana); 02504 do_bridge_masquerade(chanb, tmpchanb); 02505 02506 /* make the channels compatible, send error if we fail doing so */ 02507 if (ast_channel_make_compatible(tmpchana, tmpchanb)) { 02508 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name); 02509 astman_send_error(s, m, "Could not make channels compatible for manager bridge"); 02510 ast_hangup(tmpchana); 02511 ast_hangup(tmpchanb); 02512 return 1; 02513 } 02514 02515 /* setup the bridge thread object and start the bridge */ 02516 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) { 02517 ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno)); 02518 astman_send_error(s, m, "Unable to spawn a new bridge thread"); 02519 ast_hangup(tmpchana); 02520 ast_hangup(tmpchanb); 02521 return 1; 02522 } 02523 02524 tobj->chan = tmpchana; 02525 tobj->peer = tmpchanb; 02526 tobj->return_to_pbx = 1; 02527 02528 if (ast_true(playtone)) { 02529 if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) { 02530 if (ast_waitstream(tmpchanb, "") < 0) 02531 ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name); 02532 } 02533 } 02534 02535 ast_bridge_call_thread_launch(tobj); 02536 02537 astman_send_ack(s, m, "Launched bridge thread with success"); 02538 02539 return 0; 02540 }
static int adsi_announce_park | ( | struct ast_channel * | chan, | |
char * | parkingexten | |||
) | [static] |
Definition at line 345 of file res_features.c.
References ADSI_JUST_CENT, ast_adsi_load_session(), ast_adsi_print(), and justify.
Referenced by park_call_full().
00346 { 00347 int res; 00348 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT}; 00349 char tmp[256]; 00350 char *message[5] = {NULL, NULL, NULL, NULL, NULL}; 00351 00352 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten); 00353 message[0] = tmp; 00354 res = ast_adsi_load_session(chan, NULL, 0, 1); 00355 if (res == -1) 00356 return res; 00357 return ast_adsi_print(chan, message, justify, 1); 00358 }
AST_APP_OPTIONS | ( | bridge_exec_options | , | |
BEGIN_OPTIONS | END_OPTIONS | |||
) |
int ast_autoanswer_login | ( | struct ast_channel * | chan, | |
void * | data | |||
) |
Definition at line 2767 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().
02768 { 02769 /* We put the user in the parking list, then wake up the parking thread to be sure it looks 02770 after these channels too */ 02771 struct ast_context *con; 02772 char exten[AST_MAX_EXTENSION]; 02773 struct aauser *pu,*pl = NULL; 02774 char *s, *stringp, *aacontext, *aaexten = NULL; 02775 02776 s = ast_strdupa((void *) data); 02777 stringp=s; 02778 aacontext = strsep(&stringp, "|"); 02779 aaexten = strsep(&stringp, "|"); 02780 if (!aaexten) { 02781 aaexten = aacontext; 02782 aacontext = NULL; 02783 } 02784 if (!aaexten) { 02785 ast_log(LOG_WARNING, "AutoanswerLogin requires at least an extension!\n"); 02786 return -1; 02787 } else { 02788 if (!aacontext) { 02789 aacontext = "default"; 02790 } 02791 } 02792 02793 ast_mutex_lock(&autoanswer_lock); 02794 pu = aalot; 02795 while(pu) { 02796 if ((!strncasecmp(pu->exten, aaexten, sizeof(pu->exten)-1)) && (!strncasecmp(pu->context, aacontext, sizeof(pu->context)-1))){ 02797 if (pl) 02798 pl->next = pu->next; 02799 else 02800 aalot = pu->next; 02801 break; 02802 } 02803 pl = pu; 02804 pu = pu->next; 02805 } 02806 ast_mutex_unlock(&autoanswer_lock); 02807 if (pu) { 02808 ast_log(LOG_NOTICE, "Logout old Channel %s for %s@%s.\n",pu->chan->name, pu->exten, pu->context); 02809 manager_event(EVENT_FLAG_CALL, "AutoanswerLogout", 02810 "Channel: %s\r\n" 02811 "Uniqueid: %s\r\n" 02812 "Context: %s\r\n" 02813 "Exten: %s\r\n" 02814 ,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten); 02815 ast_hangup(pu->chan); 02816 free(pu); 02817 } 02818 pu = malloc(sizeof(struct aauser)); 02819 if (pu) { 02820 memset(pu, 0, sizeof(pu)); 02821 ast_mutex_lock(&autoanswer_lock); 02822 chan->appl = "Autoanswer"; 02823 chan->data = NULL; 02824 02825 pu->chan = chan; 02826 if (chan->_state != AST_STATE_UP) { 02827 ast_answer(chan); 02828 } 02829 02830 /* Start music on hold */ 02831 ast_moh_start(pu->chan, NULL, NULL); 02832 gettimeofday(&pu->start, NULL); 02833 strncpy(pu->exten, aaexten, sizeof(pu->exten)-1); 02834 strncpy(pu->context, aacontext, sizeof(pu->exten)-1); 02835 pu->next = aalot; 02836 aalot = pu; 02837 con = ast_context_find(aacontext); 02838 if (!con) { 02839 con = ast_context_create(NULL,aacontext, registrar); 02840 if (!con) { 02841 ast_log(LOG_ERROR, "Context '%s' does not exist and unable to create\n", aacontext); 02842 } 02843 } 02844 if (con) { 02845 snprintf(exten, sizeof(exten), "%s", aaexten); 02846 ast_add_extension2(con, 1, exten, 1, NULL, NULL, autoanswer, strdup((char *)data), free, registrar); 02847 } 02848 02849 ast_mutex_unlock(&autoanswer_lock); 02850 /* Wake up the (presumably select()ing) thread */ 02851 pthread_kill(autoanswer_thread, SIGURG); 02852 if (option_verbose > 1) 02853 ast_verbose(VERBOSE_PREFIX_2 "Autoanswer login from %s for %s@%s.\n", pu->chan->name, pu->exten, pu->context); 02854 manager_event(EVENT_FLAG_CALL, "AutoanswerLogin", 02855 "Channel: %s\r\n" 02856 "Uniqueid: %s\r\n" 02857 "Context: %s\r\n" 02858 "Exten: %s\r\n" 02859 ,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten); 02860 02861 return 0; 02862 } else { 02863 ast_log(LOG_WARNING, "Out of memory\n"); 02864 return -1; 02865 } 02866 return 0; 02867 }
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 1437 of file res_features.c.
References ast_channel::appl, ast_answer(), ast_cdr_alloc(), ast_cdr_appenduserfield(), ast_cdr_discard(), AST_CDR_FLAG_LOCKED, ast_cdr_init(), ast_cdr_merge(), ast_cdr_setdestchan(), ast_cdr_setuserfield(), ast_cdr_start(), ast_channel_bridge(), ast_channel_lock, ast_channel_setoption(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, AST_CONTROL_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_AUDIO_MODE, AST_OPTION_FLAG_REQUEST, AST_OPTION_RELAXDTMF, AST_OPTION_TDD, AST_OPTION_TONE_VERIFY, 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(), bridge_exec(), builtin_atxfer(), park_exec(), and try_calling().
01438 { 01439 /* Copy voice back and forth between the two channels. Give the peer 01440 the ability to transfer calls with '#<extension' syntax. */ 01441 struct ast_frame *f; 01442 struct ast_channel *who; 01443 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 01444 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 01445 int res; 01446 int diff; 01447 int hasfeatures=0; 01448 int hadfeatures=0; 01449 struct ast_option_header *aoh; 01450 struct ast_bridge_config backup_config; 01451 struct ast_cdr *bridge_cdr; 01452 01453 memset(&backup_config, 0, sizeof(backup_config)); 01454 01455 config->start_time = ast_tvnow(); 01456 01457 if (chan && peer) { 01458 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 01459 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 01460 } else if (chan) 01461 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 01462 01463 if (monitor_ok) { 01464 const char *monitor_exec; 01465 struct ast_channel *src = NULL; 01466 if (!monitor_app) { 01467 if (!(monitor_app = pbx_findapp("Monitor"))) 01468 monitor_ok=0; 01469 } 01470 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 01471 src = chan; 01472 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 01473 src = peer; 01474 if (monitor_app && src) { 01475 char *tmp = ast_strdupa(monitor_exec); 01476 pbx_exec(src, monitor_app, tmp); 01477 } 01478 } 01479 01480 set_config_flags(chan, peer, config); 01481 config->firstpass = 1; 01482 01483 /* Answer if need be */ 01484 if (ast_answer(chan)) 01485 return -1; 01486 peer->appl = "Bridged Call"; 01487 peer->data = chan->name; 01488 01489 /* copy the userfield from the B-leg to A-leg if applicable */ 01490 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) { 01491 char tmp[256]; 01492 if (!ast_strlen_zero(chan->cdr->userfield)) { 01493 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield); 01494 ast_cdr_appenduserfield(chan, tmp); 01495 } else 01496 ast_cdr_setuserfield(chan, peer->cdr->userfield); 01497 /* free the peer's cdr without ast_cdr_free complaining */ 01498 free(peer->cdr); 01499 peer->cdr = NULL; 01500 } 01501 01502 for (;;) { 01503 struct ast_channel *other; /* used later */ 01504 01505 res = ast_channel_bridge(chan, peer, config, &f, &who); 01506 01507 if (config->feature_timer) { 01508 /* Update time limit for next pass */ 01509 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time); 01510 config->feature_timer -= diff; 01511 if (hasfeatures) { 01512 /* Running on backup config, meaning a feature might be being 01513 activated, but that's no excuse to keep things going 01514 indefinitely! */ 01515 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) { 01516 if (option_debug) 01517 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n"); 01518 config->feature_timer = 0; 01519 who = chan; 01520 if (f) 01521 ast_frfree(f); 01522 f = NULL; 01523 res = 0; 01524 } else if (config->feature_timer <= 0) { 01525 /* Not *really* out of time, just out of time for 01526 digits to come in for features. */ 01527 if (option_debug) 01528 ast_log(LOG_DEBUG, "Timed out for feature!\n"); 01529 if (!ast_strlen_zero(peer_featurecode)) { 01530 ast_dtmf_stream(chan, peer, peer_featurecode, 0); 01531 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 01532 } 01533 if (!ast_strlen_zero(chan_featurecode)) { 01534 ast_dtmf_stream(peer, chan, chan_featurecode, 0); 01535 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 01536 } 01537 if (f) 01538 ast_frfree(f); 01539 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01540 if (!hasfeatures) { 01541 /* Restore original (possibly time modified) bridge config */ 01542 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01543 memset(&backup_config, 0, sizeof(backup_config)); 01544 } 01545 hadfeatures = hasfeatures; 01546 /* Continue as we were */ 01547 continue; 01548 } else if (!f) { 01549 /* The bridge returned without a frame and there is a feature in progress. 01550 * However, we don't think the feature has quite yet timed out, so just 01551 * go back into the bridge. */ 01552 continue; 01553 } 01554 } else { 01555 if (config->feature_timer <=0) { 01556 /* We ran out of time */ 01557 config->feature_timer = 0; 01558 who = chan; 01559 if (f) 01560 ast_frfree(f); 01561 f = NULL; 01562 res = 0; 01563 } 01564 } 01565 } 01566 if (res < 0) { 01567 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) 01568 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 01569 return -1; 01570 } 01571 01572 if (!f || (f->frametype == AST_FRAME_CONTROL && 01573 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 01574 f->subclass == AST_CONTROL_CONGESTION ) ) ) { 01575 res = -1; 01576 break; 01577 } 01578 /* many things should be sent to the 'other' channel */ 01579 other = (who == chan) ? peer : chan; 01580 if (f->frametype == AST_FRAME_CONTROL) { 01581 switch (f->subclass) { 01582 case AST_CONTROL_RINGING: 01583 case AST_CONTROL_FLASH: 01584 case -1: 01585 ast_indicate(other, f->subclass); 01586 break; 01587 case AST_CONTROL_HOLD: 01588 case AST_CONTROL_UNHOLD: 01589 ast_indicate_data(other, f->subclass, f->data, f->datalen); 01590 break; 01591 case AST_CONTROL_OPTION: 01592 aoh = f->data; 01593 /* Forward option Requests, but only ones we know are safe 01594 * These are ONLY sent by chan_iax2 and I'm not convinced that 01595 * they are useful. I haven't deleted them entirely because I 01596 * just am not sure of the ramifications of removing them. */ 01597 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 01598 switch (ntohs(aoh->option)) { 01599 case AST_OPTION_TONE_VERIFY: 01600 case AST_OPTION_TDD: 01601 case AST_OPTION_RELAXDTMF: 01602 case AST_OPTION_AUDIO_MODE: 01603 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 01604 f->datalen - sizeof(struct ast_option_header), 0); 01605 } 01606 } 01607 break; 01608 } 01609 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 01610 /* eat it */ 01611 } else if (f->frametype == AST_FRAME_DTMF) { 01612 char *featurecode; 01613 int sense; 01614 01615 hadfeatures = hasfeatures; 01616 /* This cannot overrun because the longest feature is one shorter than our buffer */ 01617 if (who == chan) { 01618 sense = FEATURE_SENSE_CHAN; 01619 featurecode = chan_featurecode; 01620 } else { 01621 sense = FEATURE_SENSE_PEER; 01622 featurecode = peer_featurecode; 01623 } 01624 /*! append the event to featurecode. we rely on the string being zero-filled, and 01625 * not overflowing it. 01626 * \todo XXX how do we guarantee the latter ? 01627 */ 01628 featurecode[strlen(featurecode)] = f->subclass; 01629 /* Get rid of the frame before we start doing "stuff" with the channels */ 01630 ast_frfree(f); 01631 f = NULL; 01632 config->feature_timer = backup_config.feature_timer; 01633 res = ast_feature_interpret(chan, peer, config, featurecode, sense); 01634 switch(res) { 01635 case FEATURE_RETURN_PASSDIGITS: 01636 ast_dtmf_stream(other, who, featurecode, 0); 01637 /* Fall through */ 01638 case FEATURE_RETURN_SUCCESS: 01639 memset(featurecode, 0, sizeof(chan_featurecode)); 01640 break; 01641 } 01642 if (res >= FEATURE_RETURN_PASSDIGITS) { 01643 res = 0; 01644 } else 01645 break; 01646 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01647 if (hadfeatures && !hasfeatures) { 01648 /* Restore backup */ 01649 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01650 memset(&backup_config, 0, sizeof(struct ast_bridge_config)); 01651 } else if (hasfeatures) { 01652 if (!hadfeatures) { 01653 /* Backup configuration */ 01654 memcpy(&backup_config, config, sizeof(struct ast_bridge_config)); 01655 /* Setup temporary config options */ 01656 config->play_warning = 0; 01657 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 01658 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 01659 config->warning_freq = 0; 01660 config->warning_sound = NULL; 01661 config->end_sound = NULL; 01662 config->start_sound = NULL; 01663 config->firstpass = 0; 01664 } 01665 config->start_time = ast_tvnow(); 01666 config->feature_timer = featuredigittimeout; 01667 if (option_debug) 01668 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer); 01669 } 01670 } 01671 if (f) 01672 ast_frfree(f); 01673 01674 } 01675 01676 /* arrange the cdrs */ 01677 bridge_cdr = ast_cdr_alloc(); 01678 if (bridge_cdr) { 01679 if (chan->cdr && peer->cdr) { /* both of them? merge */ 01680 ast_channel_lock(chan); /* lock the channel before modifing cdrs */ 01681 ast_cdr_init(bridge_cdr,chan); /* seems more logicaller to use the destination as a base, but, really, it's random */ 01682 ast_cdr_start(bridge_cdr); /* now is the time to start */ 01683 01684 /* absorb the channel cdr */ 01685 ast_cdr_merge(bridge_cdr, chan->cdr); 01686 if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED)) 01687 ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */ 01688 01689 chan->cdr = NULL; /* remove pointer to freed memory before releasing the lock */ 01690 01691 ast_channel_unlock(chan); 01692 01693 /* absorb the peer cdr */ 01694 ast_channel_lock(peer); 01695 ast_cdr_merge(bridge_cdr, peer->cdr); 01696 if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED)) 01697 ast_cdr_discard(peer->cdr); /* if locked cdrs are in peer, they are taken over in the merge */ 01698 01699 peer->cdr = NULL; 01700 ast_channel_unlock(peer); 01701 01702 ast_channel_lock(chan); 01703 chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */ 01704 ast_channel_unlock(chan); 01705 01706 } else if (chan->cdr) { 01707 01708 ast_channel_lock(chan); /* Lock before modifying CDR */ 01709 /* take the cdr from the channel - literally */ 01710 ast_cdr_init(bridge_cdr,chan); 01711 /* absorb this data */ 01712 ast_cdr_merge(bridge_cdr, chan->cdr); 01713 if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED)) 01714 ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */ 01715 chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */ 01716 ast_channel_unlock(chan); 01717 } else if (peer->cdr) { 01718 ast_channel_lock(peer); /* Lock before modifying CDR */ 01719 /* take the cdr from the peer - literally */ 01720 ast_cdr_init(bridge_cdr,peer); 01721 /* absorb this data */ 01722 ast_cdr_merge(bridge_cdr, peer->cdr); 01723 if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED)) 01724 ast_cdr_discard(peer->cdr); /* if locked cdrs are in chan, they are taken over in the merge */ 01725 peer->cdr = NULL; 01726 peer->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */ 01727 ast_channel_unlock(peer); 01728 } else { 01729 ast_channel_lock(chan); /* Lock before modifying CDR */ 01730 /* make up a new cdr */ 01731 ast_cdr_init(bridge_cdr,chan); /* eh, just pick one of them */ 01732 chan->cdr = bridge_cdr; /* */ 01733 ast_channel_unlock(chan); 01734 } 01735 if (ast_strlen_zero(bridge_cdr->dstchannel)) { 01736 if (strcmp(bridge_cdr->channel, peer->name) != 0) 01737 ast_cdr_setdestchan(bridge_cdr, peer->name); 01738 else 01739 ast_cdr_setdestchan(bridge_cdr, chan->name); 01740 } 01741 } 01742 return res; 01743 }
static void* ast_bridge_call_thread | ( | void * | data | ) | [static] |
Definition at line 285 of file res_features.c.
References ast_channel::appl, ast_bridge_call(), ast_cdr_reset(), ast_cdr_setdestchan(), ast_check_hangup(), ast_hangup(), ast_log(), ast_pbx_start(), AST_PBX_SUCCESS, ast_bridge_thread_obj::bconfig, ast_channel::cdr, ast_bridge_thread_obj::chan, ast_channel::data, free, LOG_VERBOSE, LOG_WARNING, ast_bridge_thread_obj::peer, and ast_bridge_thread_obj::return_to_pbx.
Referenced by ast_bridge_call_thread_launch().
00286 { 00287 struct ast_bridge_thread_obj *tobj = data; 00288 int res; 00289 00290 tobj->chan->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge"; 00291 tobj->chan->data = tobj->peer->name; 00292 tobj->peer->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge"; 00293 tobj->peer->data = tobj->chan->name; 00294 00295 if (tobj->chan->cdr) { 00296 ast_cdr_reset(tobj->chan->cdr, NULL); 00297 ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name); 00298 } 00299 if (tobj->peer->cdr) { 00300 ast_cdr_reset(tobj->peer->cdr, NULL); 00301 ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name); 00302 } 00303 00304 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig); 00305 00306 if (tobj->return_to_pbx) { 00307 if (!ast_check_hangup(tobj->peer)) { 00308 ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", tobj->peer->name); 00309 res = ast_pbx_start(tobj->peer); 00310 if (res != AST_PBX_SUCCESS) 00311 ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", tobj->peer->name); 00312 } else 00313 ast_hangup(tobj->peer); 00314 if (!ast_check_hangup(tobj->chan)) { 00315 ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", tobj->chan->name); 00316 res = ast_pbx_start(tobj->chan); 00317 if (res != AST_PBX_SUCCESS) 00318 ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", tobj->chan->name); 00319 } else 00320 ast_hangup(tobj->chan); 00321 } else { 00322 ast_hangup(tobj->chan); 00323 ast_hangup(tobj->peer); 00324 } 00325 00326 free(tobj); 00327 00328 return NULL; 00329 }
static void ast_bridge_call_thread_launch | ( | void * | data | ) | [static] |
Definition at line 331 of file res_features.c.
References ast_bridge_call_thread(), ast_pthread_create, and thread.
Referenced by action_bridge(), and builtin_atxfer().
00332 { 00333 pthread_t thread; 00334 pthread_attr_t attr; 00335 struct sched_param sched; 00336 00337 pthread_attr_init(&attr); 00338 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 00339 ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data); 00340 pthread_attr_destroy(&attr); 00341 memset(&sched, 0, sizeof(sched)); 00342 pthread_setschedparam(thread, SCHED_RR, &sched); 00343 }
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 1147 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().
01148 { 01149 int x; 01150 struct ast_flags features; 01151 int res = FEATURE_RETURN_PASSDIGITS; 01152 struct ast_call_feature *feature; 01153 const char *dynamic_features; 01154 char *tmp, *tok; 01155 01156 if (sense == FEATURE_SENSE_CHAN) { 01157 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL); 01158 dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"); 01159 } else { 01160 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL); 01161 dynamic_features = pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"); 01162 } 01163 if (option_debug > 2) 01164 ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, code=%s, sense=%d, features=%d dynamic=%s\n", chan->name, peer->name, code, sense, features.flags, dynamic_features); 01165 01166 ast_rwlock_rdlock(&features_lock); 01167 for (x = 0; x < FEATURES_COUNT; x++) { 01168 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) && 01169 !ast_strlen_zero(builtin_features[x].exten)) { 01170 /* Feature is up for consideration */ 01171 if (!strcmp(builtin_features[x].exten, code)) { 01172 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL); 01173 break; 01174 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) { 01175 if (res == FEATURE_RETURN_PASSDIGITS) 01176 res = FEATURE_RETURN_STOREDIGITS; 01177 } 01178 } 01179 } 01180 ast_rwlock_unlock(&features_lock); 01181 01182 if (ast_strlen_zero(dynamic_features)) 01183 return res; 01184 01185 tmp = ast_strdupa(dynamic_features); 01186 01187 while ((tok = strsep(&tmp, "#"))) { 01188 AST_LIST_LOCK(&feature_list); 01189 if (!(feature = find_dynamic_feature(tok))) { 01190 AST_LIST_UNLOCK(&feature_list); 01191 continue; 01192 } 01193 01194 /* Feature is up for consideration */ 01195 if (!strcmp(feature->exten, code)) { 01196 if (option_verbose > 2) 01197 ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok); 01198 res = feature->operation(chan, peer, config, code, sense, feature); 01199 if (res != FEATURE_RETURN_KEEPTRYING) { 01200 AST_LIST_UNLOCK(&feature_list); 01201 break; 01202 } 01203 res = FEATURE_RETURN_PASSDIGITS; 01204 } else if (!strncmp(feature->exten, code, strlen(code))) 01205 res = FEATURE_RETURN_STOREDIGITS; 01206 01207 AST_LIST_UNLOCK(&feature_list); 01208 } 01209 01210 return res; 01211 }
static struct ast_channel * ast_feature_request_and_dial | ( | struct ast_channel * | caller, | |
const char * | type, | |||
int | format, | |||
void * | data, | |||
int | timeout, | |||
int * | outstate, | |||
const char * | cid_num, | |||
const char * | cid_name, | |||
const char * | language | |||
) | [static, read] |
Definition at line 1256 of file res_features.c.
References ast_channel::_softhangup, ast_channel::_state, ast_call(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, ast_cdr_alloc(), ast_cdr_disposition(), ast_cdr_end(), ast_cdr_failed(), ast_cdr_init(), ast_cdr_setapp(), ast_cdr_start(), ast_cdr_update(), ast_channel_inherit_variables(), ast_check_hangup(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HANGUP, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_TEXT, ast_frfree, ast_hangup(), ast_indicate(), ast_log(), ast_read(), ast_request(), ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_set_callerid(), AST_STATE_UP, ast_string_field_set, ast_verbose(), ast_waitfor_n(), 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().
01257 { 01258 int state = 0; 01259 int cause = 0; 01260 int to; 01261 struct ast_channel *chan; 01262 struct ast_channel *monitor_chans[2]; 01263 struct ast_channel *active_channel; 01264 int res = 0, ready = 0; 01265 01266 if ((chan = ast_request(type, format, data, &cause))) { 01267 ast_set_callerid(chan, cid_num, cid_name, cid_num); 01268 ast_string_field_set(chan, language, language); 01269 ast_channel_inherit_variables(caller, chan); 01270 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name); 01271 if (!chan->cdr) { 01272 chan->cdr=ast_cdr_alloc(); 01273 if (chan->cdr) { 01274 ast_cdr_init(chan->cdr, chan); /* initilize our channel's cdr */ 01275 ast_cdr_start(chan->cdr); 01276 } 01277 } 01278 01279 if (!ast_call(chan, data, timeout)) { 01280 struct timeval started; 01281 int x, len = 0; 01282 char *disconnect_code = NULL, *dialed_code = NULL; 01283 01284 ast_indicate(caller, AST_CONTROL_RINGING); 01285 /* support dialing of the featuremap disconnect code while performing an attended tranfer */ 01286 ast_rwlock_rdlock(&features_lock); 01287 for (x = 0; x < FEATURES_COUNT; x++) { 01288 if (strcasecmp(builtin_features[x].sname, "disconnect")) 01289 continue; 01290 01291 disconnect_code = builtin_features[x].exten; 01292 len = strlen(disconnect_code) + 1; 01293 dialed_code = alloca(len); 01294 memset(dialed_code, 0, len); 01295 break; 01296 } 01297 ast_rwlock_unlock(&features_lock); 01298 x = 0; 01299 started = ast_tvnow(); 01300 to = timeout; 01301 while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) { 01302 struct ast_frame *f = NULL; 01303 01304 monitor_chans[0] = caller; 01305 monitor_chans[1] = chan; 01306 active_channel = ast_waitfor_n(monitor_chans, 2, &to); 01307 01308 /* see if the timeout has been violated */ 01309 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) { 01310 state = AST_CONTROL_UNHOLD; 01311 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n"); 01312 break; /*doh! timeout*/ 01313 } 01314 01315 if (!active_channel) 01316 continue; 01317 01318 if (chan && (chan == active_channel)){ 01319 f = ast_read(chan); 01320 if (f == NULL) { /*doh! where'd he go?*/ 01321 state = AST_CONTROL_HANGUP; 01322 res = 0; 01323 break; 01324 } 01325 01326 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) { 01327 if (f->subclass == AST_CONTROL_RINGING) { 01328 state = f->subclass; 01329 if (option_verbose > 2) 01330 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name); 01331 ast_indicate(caller, AST_CONTROL_RINGING); 01332 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) { 01333 state = f->subclass; 01334 if (option_verbose > 2) 01335 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name); 01336 ast_indicate(caller, AST_CONTROL_BUSY); 01337 ast_frfree(f); 01338 f = NULL; 01339 break; 01340 } else if (f->subclass == AST_CONTROL_ANSWER) { 01341 /* This is what we are hoping for */ 01342 state = f->subclass; 01343 ast_frfree(f); 01344 f = NULL; 01345 ready=1; 01346 break; 01347 } else if (f->subclass != -1) { 01348 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass); 01349 } 01350 /* else who cares */ 01351 } 01352 01353 } else if (caller && (active_channel == caller)) { 01354 f = ast_read(caller); 01355 if (f == NULL) { /*doh! where'd he go?*/ 01356 if (caller->_softhangup && !chan->_softhangup) { 01357 /* make this a blind transfer */ 01358 ready = 1; 01359 break; 01360 } 01361 state = AST_CONTROL_HANGUP; 01362 res = 0; 01363 break; 01364 } 01365 01366 if (f->frametype == AST_FRAME_DTMF) { 01367 dialed_code[x++] = f->subclass; 01368 dialed_code[x] = '\0'; 01369 if (strlen(dialed_code) == len) { 01370 x = 0; 01371 } else if (x && strncmp(dialed_code, disconnect_code, x)) { 01372 x = 0; 01373 dialed_code[x] = '\0'; 01374 } 01375 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) { 01376 /* Caller Canceled the call */ 01377 state = AST_CONTROL_UNHOLD; 01378 ast_frfree(f); 01379 f = NULL; 01380 break; 01381 } 01382 } 01383 } 01384 if (f) 01385 ast_frfree(f); 01386 } /* end while */ 01387 } else 01388 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data); 01389 } else { 01390 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data); 01391 switch(cause) { 01392 case AST_CAUSE_BUSY: 01393 state = AST_CONTROL_BUSY; 01394 break; 01395 case AST_CAUSE_CONGESTION: 01396 state = AST_CONTROL_CONGESTION; 01397 break; 01398 } 01399 } 01400 01401 ast_indicate(caller, -1); 01402 if (chan && ready) { 01403 if (chan->_state == AST_STATE_UP) 01404 state = AST_CONTROL_ANSWER; 01405 res = 0; 01406 } else if(chan) { 01407 res = -1; 01408 ast_hangup(chan); 01409 chan = NULL; 01410 } else { 01411 res = -1; 01412 } 01413 01414 if (outstate) 01415 *outstate = state; 01416 01417 if (chan && res <= 0) { 01418 if (chan->cdr || (chan->cdr = ast_cdr_alloc())) { 01419 char tmp[256]; 01420 ast_cdr_init(chan->cdr, chan); 01421 snprintf(tmp, 256, "%s/%s", type, (char *)data); 01422 ast_cdr_setapp(chan->cdr,"Dial",tmp); 01423 ast_cdr_update(chan); 01424 ast_cdr_start(chan->cdr); 01425 ast_cdr_end(chan->cdr); 01426 /* If the cause wasn't handled properly */ 01427 if (ast_cdr_disposition(chan->cdr,chan->hangupcause)) 01428 ast_cdr_failed(chan->cdr); 01429 } else { 01430 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n"); 01431 } 01432 } 01433 01434 return chan; 01435 }
struct ast_channel* ast_get_holded_call | ( | char * | uniqueid | ) | [read] |
Definition at line 2252 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().
02253 { 02254 int res=-1; 02255 struct ast_channel *peer=NULL; 02256 struct holdeduser *pu, *pl=NULL; 02257 02258 ast_mutex_lock(&holding_lock); 02259 pu = holdlist; 02260 while(pu) { 02261 if (!strncmp(uniqueid,pu->uniqueid,sizeof(pu->uniqueid))) { 02262 if (pl) 02263 pl->next = pu->next; 02264 else 02265 holdlist = pu->next; 02266 break; 02267 } 02268 pl = pu; 02269 pu = pu->next; 02270 } 02271 ast_mutex_unlock(&holding_lock); 02272 if (pu) { 02273 peer = ast_get_channel_by_uniqueid_locked(pu->uniqueid); 02274 free(pu); 02275 if (peer) { 02276 res=0; 02277 if (option_verbose > 2) 02278 ast_verbose(VERBOSE_PREFIX_3 "Channel %s removed from hold.\n", peer->name); 02279 ast_moh_stop(peer); 02280 return peer; 02281 } else { 02282 if (option_verbose > 2) 02283 ast_verbose(VERBOSE_PREFIX_3 "Could not find channel with uniqueid %s.\n", uniqueid); 02284 return NULL; 02285 } 02286 } else { 02287 ast_log(LOG_WARNING, "Could not find held channel with uniqueid %s to retrieve.\n", uniqueid); 02288 } 02289 return NULL; 02290 }
int ast_hold_call | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer | |||
) |
Definition at line 2110 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().
02111 { 02112 /* We put the user in the parking list, then wake up the parking thread to be sure it looks 02113 after these channels too */ 02114 struct holdeduser *pu; 02115 pu = malloc(sizeof(struct holdeduser)); 02116 if (pu) { 02117 memset(pu, 0, sizeof(pu)); 02118 ast_mutex_lock(&holding_lock); 02119 chan->appl = "Holded Call"; 02120 chan->data = NULL; 02121 02122 pu->chan = chan; 02123 strncpy(pu->uniqueid, chan->uniqueid, sizeof(pu->uniqueid)); 02124 strncpy(pu->uniqueidpeer, peer->uniqueid, sizeof(pu->uniqueidpeer)); 02125 /* Start music on hold */ 02126 ast_moh_start(pu->chan, NULL, NULL); 02127 gettimeofday(&pu->start, NULL); 02128 pu->next = holdlist; 02129 holdlist = pu; 02130 ast_mutex_unlock(&holding_lock); 02131 /* Wake up the (presumably select()ing) thread */ 02132 pthread_kill(holding_thread, SIGURG); 02133 02134 manager_event(EVENT_FLAG_CALL, "HoldedCall", 02135 "Channel1: %s\r\n" 02136 "Channel2: %s\r\n" 02137 "Uniqueid1: %s\r\n" 02138 "Uniqueid2: %s\r\n" 02139 ,pu->chan->name, peer->name, pu->chan->uniqueid, peer->uniqueid); 02140 02141 } else { 02142 ast_log(LOG_WARNING, "Out of memory\n"); 02143 return -1; 02144 } 02145 return 0; 02146 }
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 2721 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().
02722 { 02723 struct ast_channel *chan; 02724 struct ast_frame *f; 02725 /* Make a new, fake channel that we'll use to masquerade in the real one */ 02726 chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Autoanswer/%s", rchan->name); 02727 if (chan) { 02728 /* Let us keep track of the channel name */ 02729 ast_string_field_build(chan, name, "Autoanswer/%s",rchan->name); 02730 /* Make formats okay */ 02731 chan->readformat = rchan->readformat; 02732 chan->writeformat = rchan->writeformat; 02733 ast_channel_masquerade(chan, rchan); 02734 /* Setup the extensions and such */ 02735 strncpy(chan->context, rchan->context, sizeof(chan->context) - 1); 02736 strncpy(chan->exten, rchan->exten, sizeof(chan->exten) - 1); 02737 chan->priority = rchan->priority; 02738 /* might be dirty but we want trackable channels */ 02739 ast_string_field_build(chan, uniqueid, "%s",rchan->uniqueid); 02740 /* Make the masq execute */ 02741 f = ast_read(chan); 02742 if (f) 02743 ast_frfree(f); 02744 ast_autoanswer_login(chan, data); 02745 } else { 02746 ast_log(LOG_WARNING, "Unable to create aa channel\n"); 02747 return -1; 02748 } 02749 return 0; 02750 }
int ast_masq_hold_call | ( | struct ast_channel * | rchan, | |
struct ast_channel * | peer | |||
) |
Definition at line 2148 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.
02149 { 02150 struct ast_channel *chan; 02151 struct ast_frame *f; 02152 /* Make a new, fake channel that we'll use to masquerade in the real one */ 02153 chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Onhold/%s",rchan->name); 02154 if (chan) { 02155 /* Let us keep track of the channel name */ 02156 ast_string_field_build(chan, name, "Onhold/%s",rchan->name); 02157 /* Make formats okay */ 02158 chan->readformat = rchan->readformat; 02159 chan->writeformat = rchan->writeformat; 02160 ast_channel_masquerade(chan, rchan); 02161 /* Setup the extensions and such */ 02162 strncpy(chan->context, rchan->context, sizeof(chan->context) - 1); 02163 strncpy(chan->exten, rchan->exten, sizeof(chan->exten) - 1); 02164 chan->priority = rchan->priority; 02165 /* this might be dirty, but we need to preserve the uniqueid */ 02166 ast_string_field_build(chan, uniqueid, "%s",rchan->uniqueid); 02167 /* Make the masq execute */ 02168 f = ast_read(chan); 02169 if (f) 02170 ast_frfree(f); 02171 ast_hold_call(chan, peer); 02172 return -1; 02173 } else { 02174 ast_log(LOG_WARNING, "Unable to create holded channel\n"); 02175 return -1; 02176 } 02177 return 0; 02178 }
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 538 of file res_features.c.
References ast_channel::amaflags, ast_channel_alloc(), ast_channel_masquerade(), ast_frfree, ast_log(), ast_read(), AST_STATE_DOWN, ast_strdupa, ast_channel::context, ast_channel::exten, f, LOG_WARNING, park_call_full(), ast_channel::priority, ast_channel::readformat, set_c_e_p(), and ast_channel::writeformat.
Referenced by manager_park(), mgcp_ss(), parkandannounce_exec(), rpt_exec(), and ss_thread().
00539 { 00540 struct ast_channel *chan; 00541 struct ast_frame *f; 00542 char *orig_chan_name = NULL; 00543 00544 /* Make a new, fake channel that we'll use to masquerade in the real one */ 00545 if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) { 00546 ast_log(LOG_WARNING, "Unable to create parked channel\n"); 00547 return -1; 00548 } 00549 00550 /* Make formats okay */ 00551 chan->readformat = rchan->readformat; 00552 chan->writeformat = rchan->writeformat; 00553 ast_channel_masquerade(chan, rchan); 00554 00555 /* Setup the extensions and such */ 00556 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority); 00557 00558 /* Make the masq execute */ 00559 f = ast_read(chan); 00560 if (f) 00561 ast_frfree(f); 00562 00563 orig_chan_name = ast_strdupa(chan->name); 00564 00565 park_call_full(chan, peer, timeout, extout, orig_chan_name); 00566 00567 return 0; 00568 }
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 533 of file res_features.c.
References park_call_full().
Referenced by builtin_blindtransfer(), builtin_parkcall(), iax_park_thread(), and sip_park_thread().
00534 { 00535 return park_call_full(chan, peer, timeout, extout, NULL); 00536 }
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 218 of file res_features.c.
Referenced by builtin_blindtransfer(), dp_lookup(), handle_request_refer(), load_config(), mgcp_ss(), socket_process(), and ss_thread().
00219 { 00220 return parking_ext; 00221 }
int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
Definition at line 3109 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().
03110 { 03111 struct ast_channel *cur = NULL; 03112 int res = -1; 03113 03114 while ( (cur = ast_channel_walk_locked(cur)) != NULL) { 03115 if (!cur->pbx && 03116 (cur != chan) && 03117 (chan->pickupgroup & cur->callgroup) && 03118 ((cur->_state == AST_STATE_RINGING) || 03119 (cur->_state == AST_STATE_RING))) { 03120 break; 03121 } 03122 ast_channel_unlock(cur); 03123 } 03124 if (cur) { 03125 if (option_debug) 03126 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name); 03127 res = ast_answer(chan); 03128 if (res) 03129 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); 03130 res = ast_queue_control(chan, AST_CONTROL_ANSWER); 03131 if (res) 03132 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); 03133 res = ast_channel_masquerade(cur, chan); 03134 if (res) 03135 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */ 03136 ast_channel_unlock(cur); 03137 } else { 03138 if (option_debug) 03139 ast_log(LOG_DEBUG, "No call pickup possible...\n"); 03140 } 03141 return res; 03142 }
char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 223 of file res_features.c.
Referenced by cb_events(), get_destination(), handle_request_invite(), handle_showfeatures(), mgcp_ss(), and ss_thread().
00224 { 00225 return pickup_ext; 00226 }
void ast_register_feature | ( | struct ast_call_feature * | feature | ) |
register new feature into feature_list
register new feature into feature_set
Definition at line 1006 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().
01007 { 01008 if (!feature) { 01009 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 01010 return; 01011 } 01012 01013 AST_LIST_LOCK(&feature_list); 01014 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry); 01015 AST_LIST_UNLOCK(&feature_list); 01016 01017 if (option_verbose >= 2) 01018 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname); 01019 }
int ast_retrieve_call | ( | struct ast_channel * | chan, | |
char * | uniqueid | |||
) |
Definition at line 2180 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().
02181 { 02182 int res=-1, dres=-1; 02183 struct ast_channel *peer=NULL; 02184 struct ast_bridge_config config; 02185 02186 peer = ast_get_holded_call(uniqueid); 02187 02188 /* JK02: it helps to answer the channel if not already up */ 02189 if (chan->_state != AST_STATE_UP) { 02190 ast_answer(chan); 02191 } 02192 02193 if (peer) { 02194 ast_mutex_unlock(&peer->lock); 02195 ast_moh_stop(peer); 02196 res = ast_channel_make_compatible(chan, peer); 02197 if (res < 0) { 02198 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); 02199 ast_hangup(peer); 02200 return -1; 02201 } 02202 /* This runs sorta backwards, since we give the incoming channel control, as if it 02203 were the person called. */ 02204 if (option_verbose > 2) 02205 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to holded call %s\n", chan->name, peer->name); 02206 02207 memset(&config,0,sizeof(struct ast_bridge_config)); 02208 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 02209 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 02210 config.timelimit = 0; 02211 config.play_warning = 0; 02212 config.warning_freq = 0; 02213 config.warning_sound=NULL; 02214 res = ast_bridge_call(chan,peer,&config); 02215 02216 /* Simulate the PBX hanging up */ 02217 if (res != AST_PBX_NO_HANGUP_PEER) 02218 ast_hangup(peer); 02219 return res; 02220 } else { 02221 /* XXX Play a message XXX */ 02222 dres = ast_streamfile(chan, "pbx-invalidpark", chan->language); 02223 if (!dres) 02224 dres = ast_waitstream(chan, ""); 02225 else { 02226 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name); 02227 dres = 0; 02228 } 02229 } 02230 return res; 02231 }
int ast_retrieve_call_to_death | ( | char * | uniqueid | ) |
Definition at line 2233 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.
02234 { 02235 int res=-1; 02236 struct ast_channel *peer=NULL; 02237 02238 peer = ast_get_holded_call(uniqueid); 02239 02240 if (peer) { 02241 res=0; 02242 if (option_verbose > 2) 02243 ast_verbose(VERBOSE_PREFIX_3 "Channel %s removed from hold.\n", peer->name); 02244 ast_mutex_unlock(&peer->lock); 02245 ast_hangup(peer); 02246 } else { 02247 ast_log(LOG_WARNING, "Could not find channel with uniqueid %s to retrieve.\n", uniqueid); 02248 } 02249 return res; 02250 }
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 1022 of file res_features.c.
References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free.
01023 { 01024 if (!feature) 01025 return; 01026 01027 AST_LIST_LOCK(&feature_list); 01028 AST_LIST_REMOVE(&feature_list,feature,feature_entry); 01029 AST_LIST_UNLOCK(&feature_list); 01030 free(feature); 01031 }
static void ast_unregister_features | ( | void | ) | [static] |
Remove all features in the list.
Definition at line 1034 of file res_features.c.
References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and free.
Referenced by load_config().
01035 { 01036 struct ast_call_feature *feature; 01037 01038 AST_LIST_LOCK(&feature_list); 01039 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry))) 01040 free(feature); 01041 AST_LIST_UNLOCK(&feature_list); 01042 }
static int autoanswer_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 2994 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().
02995 { 02996 int res=0; 02997 struct ast_channel *peer=NULL; 02998 struct aauser *pu, *pl=NULL; 02999 struct ast_bridge_config config; 03000 char *s, *stringp, *aacontext, *aaexten = NULL; 03001 char datastring[80]; 03002 struct ast_module_user *u; 03003 03004 03005 if (!data) { 03006 ast_log(LOG_WARNING, "Autoanswer requires an argument (extension number)\n"); 03007 return -1; 03008 } 03009 s = ast_strdupa((void *) data); 03010 stringp=s; 03011 aacontext = strsep(&stringp, "|"); 03012 aaexten = strsep(&stringp, "|"); 03013 if (!aaexten) { 03014 aaexten = aacontext; 03015 aacontext = NULL; 03016 } 03017 if (!aaexten) { 03018 ast_log(LOG_WARNING, "AutoanswerLogin requires at least an extension!\n"); 03019 return -1; 03020 } else { 03021 if (!aacontext) { 03022 aacontext = "default"; 03023 } 03024 } 03025 03026 u = ast_module_user_add(chan); 03027 ast_mutex_lock(&autoanswer_lock); 03028 pu = aalot; 03029 while(pu) { 03030 if ((!strncasecmp(pu->exten, aaexten, sizeof(pu->exten)-1)) && (!strncasecmp(pu->context, aacontext, sizeof(pu->context)-1))){ 03031 if (pl) 03032 pl->next = pu->next; 03033 else 03034 aalot = pu->next; 03035 break; 03036 } 03037 pl = pu; 03038 pu = pu->next; 03039 } 03040 ast_mutex_unlock(&autoanswer_lock); 03041 if (pu) { 03042 peer = pu->chan; 03043 free(pu); 03044 pu = NULL; 03045 } 03046 /* JK02: it helps to answer the channel if not already up */ 03047 if (chan->_state != AST_STATE_UP) { 03048 ast_answer(chan); 03049 } 03050 03051 if (peer) { 03052 ast_moh_stop(peer); 03053 /* Play a courtesy beep in the callED channel to prefix the bridge connecting */ 03054 if (!ast_strlen_zero(courtesytone)) { 03055 if (!ast_streamfile(peer, courtesytone, peer->language)) { 03056 if (ast_waitstream(peer, "") < 0) { 03057 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 03058 ast_hangup(peer); 03059 return -1; 03060 } 03061 } 03062 } 03063 03064 res = ast_channel_make_compatible(chan, peer); 03065 if (res < 0) { 03066 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); 03067 ast_hangup(peer); 03068 return -1; 03069 } 03070 /* This runs sorta backwards, since we give the incoming channel control, as if it 03071 were the person called. */ 03072 if (option_verbose > 2) 03073 ast_verbose(VERBOSE_PREFIX_3 "Channel %s autoanswered %s\n", peer->name, chan->name); 03074 manager_event(EVENT_FLAG_CALL, "Autoanswer", 03075 "Channel: %s\r\n" 03076 "Uniqueid: %s\r\n" 03077 "Channel2: %s\r\n" 03078 "Uniqueid2: %s\r\n" 03079 "Context: %s\r\n" 03080 "Exten: %s\r\n" 03081 ,chan->name, chan->uniqueid, peer->name, peer->uniqueid, aacontext, aaexten); 03082 03083 03084 memset(&config,0,sizeof(struct ast_bridge_config)); 03085 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 03086 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 03087 config.timelimit = 0; 03088 config.play_warning = 0; 03089 config.warning_freq = 0; 03090 config.warning_sound=NULL; 03091 res = ast_bridge_call(chan,peer,&config); 03092 03093 if (option_verbose > 2) 03094 ast_verbose(VERBOSE_PREFIX_3 "returning from bridge %s\n", peer->name); 03095 /* relogin */ 03096 snprintf(datastring, sizeof(datastring) - 1, "%s|%s", aacontext, aaexten); 03097 ast_autoanswer_login(peer, datastring); 03098 return res; 03099 } else { 03100 if (option_verbose > 2) 03101 ast_verbose(VERBOSE_PREFIX_3 "Nobody logged in for autoanswer %s@%s\n", aaexten, aacontext); 03102 res = -1; 03103 } 03104 ast_module_user_remove(u); 03105 return res; 03106 }
static int autoanswer_login_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 2752 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().
02753 { 02754 int res=0; 02755 struct ast_module_user *u; 02756 02757 u = ast_module_user_add(chan); 02758 if (!data) { 02759 ast_log(LOG_WARNING, "AutoanswerLogin requires an argument (extension number)\n"); 02760 return -1; 02761 } 02762 res = ast_masq_autoanswer_login(chan, data); 02763 ast_module_user_remove(u); 02764 return res; 02765 }
static void autoanswer_reregister_extensions | ( | void | ) | [static] |
Definition at line 2869 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().
02870 { 02871 struct aauser *cur; 02872 struct ast_context *con; 02873 char exten[AST_MAX_EXTENSION]; 02874 char args[AST_MAX_EXTENSION]; 02875 02876 ast_mutex_lock(&autoanswer_lock); 02877 02878 cur=aalot; 02879 while(cur) { 02880 con = ast_context_find(cur->context); 02881 if (!con) { 02882 con = ast_context_create(NULL,cur->context, registrar); 02883 if (!con) { 02884 ast_log(LOG_ERROR, "Context '%s' does not exist and unable to create\n", cur->context); 02885 } 02886 } 02887 if (con) { 02888 snprintf(exten, sizeof(exten), "%s", cur->exten); 02889 snprintf(args, sizeof(args), "%s|%s", cur->context, cur->exten); 02890 ast_add_extension2(con, 1, exten, 1, NULL, NULL, autoanswer, strdup((char *)args), free, registrar); 02891 } 02892 cur = cur->next; 02893 } 02894 02895 ast_mutex_unlock(&autoanswer_lock); 02896 }
static int bridge_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 3387 of file res_features.c.
References ast_channel::_state, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_bridge_call(), ast_channel_alloc(), ast_channel_make_compatible(), ast_check_hangup(), AST_DECLARE_APP_ARGS, ast_get_channel_by_name_prefix_locked(), ast_hangup(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_mutex_unlock(), ast_pbx_start(), AST_PBX_SUCCESS, AST_STANDARD_APP_ARGS, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_waitstream(), BRIDGE_OPT_PLAYTONE, ast_channel::context, do_bridge_masquerade(), EVENT_FLAG_CALL, ast_channel::exten, ast_channel::lock, LOG_DEBUG, LOG_WARNING, manager_event(), option_debug, pbx_builtin_setvar_helper(), and ast_channel::priority.
Referenced by load_module().
03388 { 03389 struct ast_module_user *u; 03390 struct ast_channel *current_dest_chan, *final_dest_chan; 03391 char *tmp_data = NULL; 03392 struct ast_flags opts = { 0, }; 03393 struct ast_bridge_config bconfig = { { 0, }, }; 03394 03395 AST_DECLARE_APP_ARGS(args, 03396 AST_APP_ARG(dest_chan); 03397 AST_APP_ARG(options); 03398 ); 03399 03400 if (ast_strlen_zero(data)) { 03401 ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n"); 03402 return -1; 03403 } 03404 03405 u = ast_module_user_add(chan); 03406 03407 tmp_data = ast_strdupa(data); 03408 AST_STANDARD_APP_ARGS(args, tmp_data); 03409 if (!ast_strlen_zero(args.options)) 03410 ast_app_parse_options(bridge_exec_options, &opts, NULL, args.options); 03411 03412 /* avoid bridge with ourselves */ 03413 if (!strncmp(chan->name, args.dest_chan, 03414 strlen(chan->name) < strlen(args.dest_chan) ? 03415 strlen(chan->name) : strlen(args.dest_chan))) { 03416 ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name); 03417 manager_event(EVENT_FLAG_CALL, "BridgeExec", 03418 "Response: Failed\r\n" 03419 "Reason: Unable to bridge channel to itself\r\n" 03420 "Channel1: %s\r\n" 03421 "Channel2: %s\r\n", 03422 chan->name, args.dest_chan); 03423 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP"); 03424 ast_module_user_remove(u); 03425 return 0; 03426 } 03427 03428 /* make sure we have a valid end point */ 03429 if (!(current_dest_chan = ast_get_channel_by_name_prefix_locked(args.dest_chan, 03430 strlen(args.dest_chan)))) { 03431 ast_log(LOG_WARNING, "Bridge failed because channel %s does not exists or we " 03432 "cannot get its lock\n", args.dest_chan); 03433 manager_event(EVENT_FLAG_CALL, "BridgeExec", 03434 "Response: Failed\r\n" 03435 "Reason: Cannot grab end point\r\n" 03436 "Channel1: %s\r\n" 03437 "Channel2: %s\r\n", chan->name, args.dest_chan); 03438 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT"); 03439 ast_module_user_remove(u); 03440 return 0; 03441 } 03442 ast_mutex_unlock(¤t_dest_chan->lock); 03443 03444 /* answer the channel if needed */ 03445 if (current_dest_chan->_state != AST_STATE_UP) 03446 ast_answer(current_dest_chan); 03447 03448 /* try to allocate a place holder where current_dest_chan will be placed */ 03449 if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 03450 NULL, NULL, 0, "Bridge/%s", current_dest_chan->name))) { 03451 ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan); 03452 manager_event(EVENT_FLAG_CALL, "BridgeExec", 03453 "Response: Failed\r\n" 03454 "Reason: cannot create placeholder\r\n" 03455 "Channel1: %s\r\n" 03456 "Channel2: %s\r\n", chan->name, args.dest_chan); 03457 } 03458 do_bridge_masquerade(current_dest_chan, final_dest_chan); 03459 03460 /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */ 03461 /* try to make compatible, send error if we fail */ 03462 if (ast_channel_make_compatible(chan, final_dest_chan) < 0) { 03463 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name); 03464 manager_event(EVENT_FLAG_CALL, "BridgeExec", 03465 "Response: Failed\r\n" 03466 "Reason: Could not make channels compatible for bridge\r\n" 03467 "Channel1: %s\r\n" 03468 "Channel2: %s\r\n", chan->name, final_dest_chan->name); 03469 ast_hangup(final_dest_chan); /* may be we should return this channel to the PBX? */ 03470 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE"); 03471 ast_module_user_remove(u); 03472 return 0; 03473 } 03474 03475 /* Report that the bridge will be successfull */ 03476 manager_event(EVENT_FLAG_CALL, "BridgeExec", 03477 "Response: Success\r\n" 03478 "Channel1: %s\r\n" 03479 "Channel2: %s\r\n", chan->name, final_dest_chan->name); 03480 03481 /* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */ 03482 if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) { 03483 if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) { 03484 if (ast_waitstream(final_dest_chan, "") < 0) 03485 ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name); 03486 } 03487 } 03488 03489 /* do the bridge */ 03490 ast_bridge_call(chan, final_dest_chan, &bconfig); 03491 03492 /* the bridge has ended, set BRIDGERESULT to SUCCESS. If the other channel has not been hung up, return it to the PBX */ 03493 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS"); 03494 if (!ast_check_hangup(final_dest_chan)) { 03495 if (option_debug) { 03496 ast_log(LOG_DEBUG, "starting new PBX in %s,%s,%d for chan %s\n", 03497 final_dest_chan->context, final_dest_chan->exten, 03498 final_dest_chan->priority, final_dest_chan->name); 03499 } 03500 03501 if (ast_pbx_start(final_dest_chan) != AST_PBX_SUCCESS) { 03502 ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name); 03503 ast_hangup(final_dest_chan); 03504 } else if (option_debug) 03505 ast_log(LOG_DEBUG, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name); 03506 } else { 03507 if (option_debug) 03508 ast_log(LOG_DEBUG, "hangup chan %s since the other endpoint has hung up\n", final_dest_chan->name); 03509 ast_hangup(final_dest_chan); 03510 } 03511 03512 ast_module_user_remove(u); 03513 03514 return 0; 03515 }
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 846 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(), ast_channel::visible_indication, and ast_channel::writeformat.
00847 { 00848 struct ast_channel *transferer; 00849 struct ast_channel *transferee; 00850 const char *transferer_real_context; 00851 char xferto[256] = ""; 00852 int res; 00853 int outstate=0; 00854 struct ast_channel *newchan; 00855 struct ast_channel *xferchan; 00856 struct ast_bridge_thread_obj *tobj; 00857 struct ast_bridge_config bconfig; 00858 struct ast_frame *f; 00859 int l; 00860 00861 if (option_debug) 00862 ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense); 00863 set_peers(&transferer, &transferee, peer, chan, sense); 00864 transferer_real_context = real_ctx(transferer, transferee); 00865 /* Start autoservice on chan while we talk to the originator */ 00866 ast_autoservice_start(transferee); 00867 ast_indicate(transferee, AST_CONTROL_HOLD); 00868 00869 /* Transfer */ 00870 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY); 00871 if (res < 0) { 00872 finishup(transferee); 00873 return res; 00874 } 00875 if (res > 0) /* If they've typed a digit already, handle it */ 00876 xferto[0] = (char) res; 00877 00878 /* this is specific of atxfer */ 00879 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 00880 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */ 00881 finishup(transferee); 00882 return res; 00883 } 00884 if (res == 0) { 00885 ast_log(LOG_WARNING, "Did not read data.\n"); 00886 finishup(transferee); 00887 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, "")) 00888 return -1; 00889 return FEATURE_RETURN_SUCCESS; 00890 } 00891 00892 /* valid extension, res == 1 */ 00893 if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) { 00894 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context); 00895 finishup(transferee); 00896 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, "")) 00897 return -1; 00898 return FEATURE_RETURN_SUCCESS; 00899 } 00900 00901 l = strlen(xferto); 00902 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); /* append context */ 00903 newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats), 00904 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, transferer->language); 00905 ast_indicate(transferer, -1); 00906 if (!newchan) { 00907 finishup(transferee); 00908 /* any reason besides user requested cancel and busy triggers the failed sound */ 00909 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY && 00910 ast_stream_and_wait(transferer, xferfailsound, transferer->language, "")) 00911 return -1; 00912 return FEATURE_RETURN_SUCCESS; 00913 } 00914 00915 if (check_compat(transferer, newchan)) { 00916 /* we do mean transferee here, NOT transferer */ 00917 finishup(transferee); 00918 return -1; 00919 } 00920 memset(&bconfig,0,sizeof(struct ast_bridge_config)); 00921 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 00922 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 00923 res = ast_bridge_call(transferer, newchan, &bconfig); 00924 if (newchan->_softhangup || !transferer->_softhangup) { 00925 ast_hangup(newchan); 00926 if (ast_stream_and_wait(transferer, xfersound, transferer->language, "")) 00927 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 00928 finishup(transferee); 00929 transferer->_softhangup = 0; 00930 return FEATURE_RETURN_SUCCESS; 00931 } 00932 00933 if (check_compat(transferee, newchan)) { 00934 finishup(transferee); 00935 return -1; 00936 } 00937 00938 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00939 00940 if ((ast_autoservice_stop(transferee) < 0) 00941 || (ast_waitfordigit(transferee, 100) < 0) 00942 || (ast_waitfordigit(newchan, 100) < 0) 00943 || ast_check_hangup(transferee) 00944 || ast_check_hangup(newchan)) { 00945 ast_hangup(newchan); 00946 return -1; 00947 } 00948 00949 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name); 00950 if (!xferchan) { 00951 ast_hangup(newchan); 00952 return -1; 00953 } 00954 /* Make formats okay */ 00955 xferchan->visible_indication = transferer->visible_indication; 00956 xferchan->readformat = transferee->readformat; 00957 xferchan->writeformat = transferee->writeformat; 00958 ast_channel_masquerade(xferchan, transferee); 00959 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority); 00960 xferchan->_state = AST_STATE_UP; 00961 ast_clear_flag(xferchan, AST_FLAGS_ALL); 00962 xferchan->_softhangup = 0; 00963 00964 if ((f = ast_read(xferchan))) 00965 ast_frfree(f); 00966 00967 newchan->_state = AST_STATE_UP; 00968 ast_clear_flag(newchan, AST_FLAGS_ALL); 00969 newchan->_softhangup = 0; 00970 00971 tobj = ast_calloc(1, sizeof(struct ast_bridge_thread_obj)); 00972 if (!tobj) { 00973 ast_hangup(xferchan); 00974 ast_hangup(newchan); 00975 return -1; 00976 } 00977 tobj->chan = newchan; 00978 tobj->peer = xferchan; 00979 tobj->bconfig = *config; 00980 00981 if (ast_stream_and_wait(newchan, xfersound, newchan->language, "")) 00982 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 00983 ast_bridge_call_thread_launch(tobj); 00984 return -1; /* XXX meaning the channel is bridged ? */ 00985 }
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 632 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.
00633 { 00634 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 00635 int x = 0; 00636 size_t len; 00637 struct ast_channel *caller_chan, *callee_chan; 00638 00639 if (!monitor_ok) { 00640 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 00641 return -1; 00642 } 00643 00644 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) { 00645 monitor_ok = 0; 00646 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 00647 return -1; 00648 } 00649 00650 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 00651 00652 if (!ast_strlen_zero(courtesytone)) { 00653 if (ast_autoservice_start(callee_chan)) 00654 return -1; 00655 if (ast_stream_and_wait(caller_chan, courtesytone, caller_chan->language, "")) { 00656 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 00657 ast_autoservice_stop(callee_chan); 00658 return -1; 00659 } 00660 if (ast_autoservice_stop(callee_chan)) 00661 return -1; 00662 } 00663 00664 if (callee_chan->monitor) { 00665 if (option_verbose > 3) 00666 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code); 00667 ast_monitor_stop(callee_chan, 1); 00668 return FEATURE_RETURN_SUCCESS; 00669 } 00670 00671 if (caller_chan && callee_chan) { 00672 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT"); 00673 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR"); 00674 00675 if (!touch_format) 00676 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT"); 00677 00678 if (!touch_monitor) 00679 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR"); 00680 00681 if (touch_monitor) { 00682 len = strlen(touch_monitor) + 50; 00683 args = alloca(len); 00684 touch_filename = alloca(len); 00685 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor); 00686 snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename); 00687 } else { 00688 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name)); 00689 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name)); 00690 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 00691 args = alloca(len); 00692 touch_filename = alloca(len); 00693 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id); 00694 snprintf(args, len, "%s|%s|m", S_OR(touch_format, "wav"), touch_filename); 00695 } 00696 00697 for( x = 0; x < strlen(args); x++) { 00698 if (args[x] == '/') 00699 args[x] = '-'; 00700 } 00701 00702 if (option_verbose > 3) 00703 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args); 00704 00705 pbx_exec(callee_chan, monitor_app, args); 00706 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 00707 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 00708 00709 return FEATURE_RETURN_SUCCESS; 00710 } 00711 00712 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); 00713 return -1; 00714 }
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 743 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.
00744 { 00745 struct ast_channel *transferer; 00746 struct ast_channel *transferee; 00747 const char *transferer_real_context; 00748 char xferto[256]; 00749 int res; 00750 00751 set_peers(&transferer, &transferee, peer, chan, sense); 00752 transferer_real_context = real_ctx(transferer, transferee); 00753 /* Start autoservice on chan while we talk to the originator */ 00754 ast_autoservice_start(transferee); 00755 ast_indicate(transferee, AST_CONTROL_HOLD); 00756 00757 memset(xferto, 0, sizeof(xferto)); 00758 00759 /* Transfer */ 00760 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY); 00761 if (res < 0) { 00762 finishup(transferee); 00763 return -1; /* error ? */ 00764 } 00765 if (res > 0) /* If they've typed a digit already, handle it */ 00766 xferto[0] = (char) res; 00767 00768 ast_stopstream(transferer); 00769 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 00770 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */ 00771 finishup(transferee); 00772 return res; 00773 } 00774 if (!strcmp(xferto, ast_parking_ext())) { 00775 res = finishup(transferee); 00776 if (res) 00777 res = -1; 00778 else if (!ast_park_call(transferee, transferer, 0, NULL)) { /* success */ 00779 /* We return non-zero, but tell the PBX not to hang the channel when 00780 the thread dies -- We have to be careful now though. We are responsible for 00781 hanging up the channel, else it will never be hung up! */ 00782 00783 return (transferer == peer) ? AST_PBX_KEEPALIVE : AST_PBX_NO_HANGUP_PEER; 00784 } else { 00785 ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name); 00786 } 00787 /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */ 00788 } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) { 00789 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", transferee->name); 00790 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name); 00791 res=finishup(transferee); 00792 if (!transferer->cdr) { 00793 transferer->cdr=ast_cdr_alloc(); 00794 if (transferer) { 00795 ast_cdr_init(transferer->cdr, transferer); /* initilize our channel's cdr */ 00796 ast_cdr_start(transferer->cdr); 00797 } 00798 } 00799 if (transferer->cdr) { 00800 ast_cdr_setdestchan(transferer->cdr, transferee->name); 00801 ast_cdr_setapp(transferer->cdr, "BLINDTRANSFER",""); 00802 } 00803 if (!transferee->pbx) { 00804 /* Doh! Use our handy async_goto functions */ 00805 if (option_verbose > 2) 00806 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n" 00807 ,transferee->name, xferto, transferer_real_context); 00808 if (ast_async_goto(transferee, transferer_real_context, xferto, 1)) 00809 ast_log(LOG_WARNING, "Async goto failed :-(\n"); 00810 res = -1; 00811 } else { 00812 /* Set the channel's new extension, since it exists, using transferer context */ 00813 set_c_e_p(transferee, transferer_real_context, xferto, 0); 00814 } 00815 check_goto_on_transfer(transferer); 00816 return res; 00817 } else { 00818 if (option_verbose > 2) 00819 ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context); 00820 } 00821 if (ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0 ) { 00822 finishup(transferee); 00823 return -1; 00824 } 00825 ast_stopstream(transferer); 00826 res = finishup(transferee); 00827 if (res) { 00828 if (option_verbose > 1) 00829 ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name); 00830 return res; 00831 } 00832 return FEATURE_RETURN_SUCCESS; 00833 }
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 716 of file res_features.c.
References ast_verbose(), FEATURE_RETURN_HANGUP, option_verbose, and VERBOSE_PREFIX_3.
00717 { 00718 if (option_verbose > 3) 00719 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code); 00720 return FEATURE_RETURN_HANGUP; 00721 }
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 599 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().
00600 { 00601 struct ast_channel *parker; 00602 struct ast_channel *parkee; 00603 int res = 0; 00604 struct ast_module_user *u; 00605 00606 u = ast_module_user_add(chan); 00607 00608 set_peers(&parker, &parkee, peer, chan, sense); 00609 /* Setup the exten/priority to be s/1 since we don't know 00610 where this call should return */ 00611 strcpy(chan->exten, "s"); 00612 chan->priority = 1; 00613 if (chan->_state != AST_STATE_UP) 00614 res = ast_answer(chan); 00615 if (!res) 00616 res = ast_safe_sleep(chan, 1000); 00617 if (!res) 00618 res = ast_park_call(parkee, parker, 0, NULL); 00619 00620 ast_module_user_remove(u); 00621 00622 if (!res) { 00623 if (sense == FEATURE_SENSE_CHAN) 00624 res = AST_PBX_NO_HANGUP_PEER; 00625 else 00626 res = AST_PBX_KEEPALIVE; 00627 } 00628 return res; 00629 00630 }
static int check_compat | ( | struct ast_channel * | c, | |
struct ast_channel * | newchan | |||
) | [static] |
Definition at line 835 of file res_features.c.
References ast_channel_make_compatible(), ast_hangup(), ast_log(), and LOG_WARNING.
Referenced by builtin_atxfer().
00836 { 00837 if (ast_channel_make_compatible(c, newchan) < 0) { 00838 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", 00839 c->name, newchan->name); 00840 ast_hangup(newchan); 00841 return -1; 00842 } 00843 return 0; 00844 }
static void check_goto_on_transfer | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 246 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().
00247 { 00248 struct ast_channel *xferchan; 00249 const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR"); 00250 char *x, *goto_on_transfer; 00251 struct ast_frame *f; 00252 00253 if (ast_strlen_zero(val)) 00254 return; 00255 00256 goto_on_transfer = ast_strdupa(val); 00257 00258 if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, chan->name))) 00259 return; 00260 00261 for (x = goto_on_transfer; x && *x; x++) { 00262 if (*x == '^') 00263 *x = '|'; 00264 } 00265 /* Make formats okay */ 00266 xferchan->readformat = chan->readformat; 00267 xferchan->writeformat = chan->writeformat; 00268 ast_channel_masquerade(xferchan, chan); 00269 ast_parseable_goto(xferchan, goto_on_transfer); 00270 xferchan->_state = AST_STATE_UP; 00271 ast_clear_flag(xferchan, AST_FLAGS_ALL); 00272 xferchan->_softhangup = 0; 00273 if ((f = ast_read(xferchan))) { 00274 ast_frfree(f); 00275 f = NULL; 00276 ast_pbx_start(xferchan); 00277 } else { 00278 ast_hangup(xferchan); 00279 } 00280 }
static void* do_autoanswer_thread | ( | void * | ignore | ) | [static] |
Definition at line 2897 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().
02898 { 02899 int ms, tms, max; 02900 struct ast_context *con; 02901 char exten[AST_MAX_EXTENSION]; 02902 struct aauser *pu, *pl, *pt = NULL; 02903 struct timeval tv; 02904 struct ast_frame *f; 02905 int x; 02906 fd_set rfds, efds; 02907 fd_set nrfds, nefds; 02908 FD_ZERO(&rfds); 02909 FD_ZERO(&efds); 02910 for (;;) { 02911 ms = -1; 02912 max = -1; 02913 ast_mutex_lock(&autoanswer_lock); 02914 pl = NULL; 02915 pu = aalot; 02916 gettimeofday(&tv, NULL); 02917 FD_ZERO(&nrfds); 02918 FD_ZERO(&nefds); 02919 while(pu) { 02920 tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000; 02921 for (x=0;x<AST_MAX_FDS;x++) { 02922 if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) { 02923 if (FD_ISSET(pu->chan->fds[x], &efds)) 02924 ast_set_flag(pu->chan, AST_FLAG_EXCEPTION); 02925 else 02926 ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION); 02927 pu->chan->fdno = x; 02928 /* See if they need servicing */ 02929 f = ast_read(pu->chan); 02930 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) { 02931 /* There's a problem, hang them up*/ 02932 if (option_verbose > 1) 02933 ast_verbose(VERBOSE_PREFIX_2 "%s logged out of autoanswer app\n", pu->chan->name); 02934 manager_event(EVENT_FLAG_CALL, "AutoanswerLogout", 02935 "Channel: %s\r\n" 02936 "Uniqueid: %s\r\n" 02937 "Context: %s\r\n" 02938 "Exten: %s\r\n" 02939 ,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten); 02940 ast_hangup(pu->chan); 02941 con = ast_context_find(pu->context); 02942 if (con) { 02943 snprintf(exten, sizeof(exten), "%s", pu->exten); 02944 if (ast_context_remove_extension2(con, exten, 1, registrar)) 02945 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 02946 } else { 02947 ast_log(LOG_WARNING, "Whoa, no %s context?\n", pu->exten); 02948 } 02949 /* And take them out of the parking lot */ 02950 if (pl) 02951 pl->next = pu->next; 02952 else 02953 aalot = pu->next; 02954 pt = pu; 02955 pu = pu->next; 02956 free(pt); 02957 break; 02958 } else { 02959 /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ 02960 ast_frfree(f); 02961 goto std; /* XXX Ick: jumping into an else statement??? XXX */ 02962 } 02963 } 02964 } 02965 if (x >= AST_MAX_FDS) { 02966 std: for (x=0;x<AST_MAX_FDS;x++) { 02967 /* Keep this one for next one */ 02968 if (pu->chan->fds[x] > -1) { 02969 FD_SET(pu->chan->fds[x], &nrfds); 02970 FD_SET(pu->chan->fds[x], &nefds); 02971 if (pu->chan->fds[x] > max) 02972 max = pu->chan->fds[x]; 02973 } 02974 } 02975 /* Keep track of our longest wait */ 02976 if ((tms < ms) || (ms < 0)) 02977 ms = tms; 02978 pl = pu; 02979 pu = pu->next; 02980 } 02981 } 02982 ast_mutex_unlock(&autoanswer_lock); 02983 rfds = nrfds; 02984 efds = nefds; 02985 tv.tv_sec = ms / 1000; 02986 tv.tv_usec = (ms % 1000) * 1000; 02987 /* Wait for something to happen */ 02988 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL); 02989 pthread_testcancel(); 02990 } 02991 return NULL; /* Never reached */ 02992 }
static void do_bridge_masquerade | ( | struct ast_channel * | chan, | |
struct ast_channel * | tmpchan | |||
) | [static] |
Definition at line 2431 of file res_features.c.
References ast_channel::_state, ast_channel_masquerade(), ast_do_masquerade(), ast_explicit_goto(), ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_setstate(), ast_channel::context, ast_channel::exten, ast_channel::lock, ast_channel::priority, ast_channel::readformat, and ast_channel::writeformat.
Referenced by action_bridge(), and bridge_exec().
02432 { 02433 ast_moh_stop(chan); 02434 ast_mutex_lock(&chan->lock); 02435 ast_setstate(tmpchan, chan->_state); 02436 tmpchan->readformat = chan->readformat; 02437 tmpchan->writeformat = chan->writeformat; 02438 ast_channel_masquerade(tmpchan, chan); 02439 ast_mutex_lock(&tmpchan->lock); 02440 ast_do_masquerade(tmpchan); 02441 /* when returning from bridge, the channel will continue at the next priority */ 02442 ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1); 02443 ast_mutex_unlock(&tmpchan->lock); 02444 ast_mutex_unlock(&chan->lock); 02445 }
static void* do_holding_thread | ( | void * | ignore | ) | [static] |
Definition at line 2293 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().
02294 { 02295 int ms, tms, max; 02296 struct holdeduser *pu, *pl, *pt = NULL; 02297 struct timeval tv; 02298 struct ast_frame *f; 02299 int x; 02300 fd_set rfds, efds; 02301 fd_set nrfds, nefds; 02302 FD_ZERO(&rfds); 02303 FD_ZERO(&efds); 02304 for (;;) { 02305 ms = -1; 02306 max = -1; 02307 ast_mutex_lock(&holding_lock); 02308 pl = NULL; 02309 pu = holdlist; 02310 gettimeofday(&tv, NULL); 02311 FD_ZERO(&nrfds); 02312 FD_ZERO(&nefds); 02313 while(pu) { 02314 tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000; 02315 for (x=0;x<AST_MAX_FDS;x++) { 02316 if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) { 02317 if (FD_ISSET(pu->chan->fds[x], &efds)) 02318 ast_set_flag(pu->chan, AST_FLAG_EXCEPTION); 02319 else 02320 ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION); 02321 pu->chan->fdno = x; 02322 /* See if they need servicing */ 02323 f = ast_read(pu->chan); 02324 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) { 02325 /* There's a problem, hang them up*/ 02326 if (option_verbose > 1) 02327 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being onhold\n", pu->chan->name); 02328 ast_hangup(pu->chan); 02329 /* find the corresponding channel and hang them up too! */ 02330 /* but only if it is not bridged yet! */ 02331 /* And take them out of the parking lot */ 02332 if (pl) 02333 pl->next = pu->next; 02334 else 02335 holdlist = pu->next; 02336 pt = pu; 02337 pu = pu->next; 02338 free(pt); 02339 break; 02340 } else { 02341 /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ 02342 ast_frfree(f); 02343 goto std; /* XXX Ick: jumping into an else statement??? XXX */ 02344 } 02345 } 02346 } 02347 if (x >= AST_MAX_FDS) { 02348 std: for (x=0;x<AST_MAX_FDS;x++) { 02349 /* Keep this one for next one */ 02350 if (pu->chan->fds[x] > -1) { 02351 FD_SET(pu->chan->fds[x], &nrfds); 02352 FD_SET(pu->chan->fds[x], &nefds); 02353 if (pu->chan->fds[x] > max) 02354 max = pu->chan->fds[x]; 02355 } 02356 } 02357 /* Keep track of our longest wait */ 02358 if ((tms < ms) || (ms < 0)) 02359 ms = tms; 02360 pl = pu; 02361 pu = pu->next; 02362 } 02363 } 02364 ast_mutex_unlock(&holding_lock); 02365 rfds = nrfds; 02366 efds = nefds; 02367 tv.tv_sec = ms / 1000; 02368 tv.tv_usec = (ms % 1000) * 1000; 02369 /* Wait for something to happen */ 02370 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL); 02371 pthread_testcancel(); 02372 } 02373 return NULL; /* Never reached */ 02374 }
static void* do_parking_thread | ( | void * | ignore | ) | [static] |
Take care of parked calls and unpark them if needed.
Definition at line 1762 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().
01763 { 01764 fd_set rfds, efds; /* results from previous select, to be preserved across loops. */ 01765 FD_ZERO(&rfds); 01766 FD_ZERO(&efds); 01767 01768 for (;;) { 01769 struct parkeduser *pu, *pl, *pt = NULL; 01770 int ms = -1; /* select timeout, uninitialized */ 01771 int max = -1; /* max fd, none there yet */ 01772 fd_set nrfds, nefds; /* args for the next select */ 01773 FD_ZERO(&nrfds); 01774 FD_ZERO(&nefds); 01775 01776 ast_mutex_lock(&parking_lock); 01777 pl = NULL; 01778 pu = parkinglot; 01779 /* navigate the list with prev-cur pointers to support removals */ 01780 while (pu) { 01781 struct ast_channel *chan = pu->chan; /* shorthand */ 01782 int tms; /* timeout for this item */ 01783 int x; /* fd index in channel */ 01784 struct ast_context *con; 01785 01786 if (pu->notquiteyet) { /* Pretend this one isn't here yet */ 01787 pl = pu; 01788 pu = pu->next; 01789 continue; 01790 } 01791 tms = ast_tvdiff_ms(ast_tvnow(), pu->start); 01792 if (tms > pu->parkingtime) { 01793 ast_indicate(chan, AST_CONTROL_UNHOLD); 01794 /* Get chan, exten from derived kludge */ 01795 if (pu->peername[0]) { 01796 char *peername = ast_strdupa(pu->peername); 01797 char *cp = strrchr(peername, '-'); 01798 if (cp) 01799 *cp = 0; 01800 con = ast_context_find(parking_con_dial); 01801 if (!con) { 01802 con = ast_context_create(NULL, parking_con_dial, registrar); 01803 if (!con) 01804 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial); 01805 } 01806 if (con) { 01807 char returnexten[AST_MAX_EXTENSION]; 01808 snprintf(returnexten, sizeof(returnexten), "%s|30|t", peername); 01809 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar); 01810 } 01811 set_c_e_p(chan, parking_con_dial, peername, 1); 01812 } else { 01813 /* They've been waiting too long, send them back to where they came. Theoretically they 01814 should have their original extensions and such, but we copy to be on the safe side */ 01815 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 01816 } 01817 01818 post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan); 01819 01820 if (option_verbose > 1) 01821 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); 01822 /* Start up the PBX, or hang them up */ 01823 if (ast_pbx_start(chan)) { 01824 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name); 01825 ast_hangup(chan); 01826 } 01827 /* And take them out of the parking lot */ 01828 if (pl) 01829 pl->next = pu->next; 01830 else 01831 parkinglot = pu->next; 01832 pt = pu; 01833 pu = pu->next; 01834 con = ast_context_find(parking_con); 01835 if (con) { 01836 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL)) 01837 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 01838 else 01839 notify_metermaids(pt->parkingexten, parking_con); 01840 } else 01841 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 01842 free(pt); 01843 } else { /* still within parking time, process descriptors */ 01844 for (x = 0; x < AST_MAX_FDS; x++) { 01845 struct ast_frame *f; 01846 01847 if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds))) 01848 continue; /* nothing on this descriptor */ 01849 01850 if (FD_ISSET(chan->fds[x], &efds)) 01851 ast_set_flag(chan, AST_FLAG_EXCEPTION); 01852 else 01853 ast_clear_flag(chan, AST_FLAG_EXCEPTION); 01854 chan->fdno = x; 01855 01856 /* See if they need servicing */ 01857 f = ast_read(chan); 01858 if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP)) { 01859 if (f) 01860 ast_frfree(f); 01861 post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan); 01862 01863 /* There's a problem, hang them up*/ 01864 if (option_verbose > 1) 01865 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name); 01866 ast_hangup(chan); 01867 /* And take them out of the parking lot */ 01868 if (pl) 01869 pl->next = pu->next; 01870 else 01871 parkinglot = pu->next; 01872 pt = pu; 01873 pu = pu->next; 01874 con = ast_context_find(parking_con); 01875 if (con) { 01876 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL)) 01877 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 01878 else 01879 notify_metermaids(pt->parkingexten, parking_con); 01880 } else 01881 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 01882 free(pt); 01883 break; 01884 } else { 01885 /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ 01886 ast_frfree(f); 01887 if (pu->moh_trys < 3 && !chan->generatordata) { 01888 if (option_debug) 01889 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n"); 01890 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 01891 S_OR(parkmohclass, NULL), 01892 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 01893 pu->moh_trys++; 01894 } 01895 goto std; /*! \todo XXX Ick: jumping into an else statement??? XXX */ 01896 } 01897 01898 } /* end for */ 01899 if (x >= AST_MAX_FDS) { 01900 std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */ 01901 if (chan->fds[x] > -1) { 01902 FD_SET(chan->fds[x], &nrfds); 01903 FD_SET(chan->fds[x], &nefds); 01904 if (chan->fds[x] > max) 01905 max = chan->fds[x]; 01906 } 01907 } 01908 /* Keep track of our shortest wait */ 01909 if (tms < ms || ms < 0) 01910 ms = tms; 01911 pl = pu; 01912 pu = pu->next; 01913 } 01914 } 01915 } /* end while */ 01916 ast_mutex_unlock(&parking_lock); 01917 rfds = nrfds; 01918 efds = nefds; 01919 { 01920 struct timeval tv = ast_samp2tv(ms, 1000); 01921 /* Wait for something to happen */ 01922 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL); 01923 } 01924 pthread_testcancel(); 01925 } 01926 return NULL; /* Never reached */ 01927 }
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 1058 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().
01059 { 01060 struct ast_app *app; 01061 struct ast_call_feature *feature = data; 01062 struct ast_channel *work, *idle; 01063 int res; 01064 01065 if (!feature) { /* shouldn't ever happen! */ 01066 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n"); 01067 return -1; 01068 } 01069 01070 if (sense == FEATURE_SENSE_CHAN) { 01071 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 01072 return FEATURE_RETURN_KEEPTRYING; 01073 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 01074 work = chan; 01075 idle = peer; 01076 } else { 01077 work = peer; 01078 idle = chan; 01079 } 01080 } else { 01081 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 01082 return FEATURE_RETURN_KEEPTRYING; 01083 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 01084 work = peer; 01085 idle = chan; 01086 } else { 01087 work = chan; 01088 idle = peer; 01089 } 01090 } 01091 01092 if (!(app = pbx_findapp(feature->app))) { 01093 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app); 01094 return -2; 01095 } 01096 01097 ast_autoservice_start(idle); 01098 01099 if (!ast_strlen_zero(feature->moh_class)) 01100 ast_moh_start(idle, feature->moh_class, NULL); 01101 01102 res = pbx_exec(work, app, feature->app_args); 01103 01104 if (!ast_strlen_zero(feature->moh_class)) 01105 ast_moh_stop(idle); 01106 01107 ast_autoservice_stop(idle); 01108 01109 if (res == AST_PBX_KEEPALIVE) 01110 return FEATURE_RETURN_PBX_KEEPALIVE; 01111 else if (res == AST_PBX_NO_HANGUP_PEER) 01112 return FEATURE_RETURN_NO_HANGUP_PEER; 01113 else if (res) 01114 return FEATURE_RETURN_SUCCESSBREAK; 01115 01116 return FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */ 01117 }
static struct ast_call_feature* find_dynamic_feature | ( | const char * | name | ) | [static, read] |
find a feature by name
Definition at line 1045 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().
01046 { 01047 struct ast_call_feature *tmp; 01048 01049 AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) { 01050 if (!strcasecmp(tmp->sname, name)) 01051 break; 01052 } 01053 01054 return tmp; 01055 }
static int finishup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 723 of file res_features.c.
References ast_autoservice_stop(), AST_CONTROL_UNHOLD, and ast_indicate().
Referenced by builtin_atxfer(), and builtin_blindtransfer().
00724 { 00725 ast_indicate(chan, AST_CONTROL_UNHOLD); 00726 00727 return ast_autoservice_stop(chan); 00728 }
static int handle_autoanswer | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 2687 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.
02688 { 02689 struct aauser *cur; 02690 02691 ast_cli(fd, "%25s %10s %15s \n", "Channel" 02692 , "Extension", "Context"); 02693 02694 ast_mutex_lock(&autoanswer_lock); 02695 02696 cur=aalot; 02697 while(cur) { 02698 ast_cli(fd, "%25s %10s %15s\n",cur->chan->name, cur->exten, cur->context); 02699 02700 cur = cur->next; 02701 } 02702 02703 ast_mutex_unlock(&autoanswer_lock); 02704 02705 return RESULT_SUCCESS; 02706 }
static int handle_parkedcalls | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 2546 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.
02547 { 02548 struct parkeduser *cur; 02549 int numparked = 0; 02550 02551 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel" 02552 , "Context", "Extension", "Pri", "Timeout"); 02553 02554 ast_mutex_lock(&parking_lock); 02555 02556 for (cur = parkinglot; cur; cur = cur->next) { 02557 ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n" 02558 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten 02559 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)); 02560 02561 numparked++; 02562 } 02563 ast_mutex_unlock(&parking_lock); 02564 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : ""); 02565 02566 02567 return RESULT_SUCCESS; 02568 }
static int handle_showfeatures | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 2386 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.
02387 { 02388 int i; 02389 struct ast_call_feature *feature; 02390 char format[] = "%-25s %-7s %-7s\n"; 02391 02392 ast_cli(fd, format, "Builtin Feature", "Default", "Current"); 02393 ast_cli(fd, format, "---------------", "-------", "-------"); 02394 02395 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */ 02396 02397 ast_rwlock_rdlock(&features_lock); 02398 for (i = 0; i < FEATURES_COUNT; i++) 02399 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten); 02400 ast_rwlock_unlock(&features_lock); 02401 02402 ast_cli(fd, "\n"); 02403 ast_cli(fd, format, "Dynamic Feature", "Default", "Current"); 02404 ast_cli(fd, format, "---------------", "-------", "-------"); 02405 if (AST_LIST_EMPTY(&feature_list)) 02406 ast_cli(fd, "(none)\n"); 02407 else { 02408 AST_LIST_LOCK(&feature_list); 02409 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) 02410 ast_cli(fd, format, feature->sname, "no def", feature->exten); 02411 AST_LIST_UNLOCK(&feature_list); 02412 } 02413 ast_cli(fd, "\nCall parking\n"); 02414 ast_cli(fd, "------------\n"); 02415 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext); 02416 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con); 02417 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop); 02418 ast_cli(fd,"\n"); 02419 02420 return RESULT_SUCCESS; 02421 }
static int load_config | ( | void | ) | [static] |
Definition at line 3159 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.
03160 { 03161 int start = 0, end = 0; 03162 int res; 03163 struct ast_context *con = NULL; 03164 struct ast_config *cfg = NULL; 03165 struct ast_variable *var = NULL; 03166 char old_parking_ext[AST_MAX_EXTENSION]; 03167 char old_parking_con[AST_MAX_EXTENSION] = ""; 03168 03169 if (!ast_strlen_zero(parking_con)) { 03170 strcpy(old_parking_ext, parking_ext); 03171 strcpy(old_parking_con, parking_con); 03172 } 03173 03174 /* Reset to defaults */ 03175 strcpy(parking_con, "parkedcalls"); 03176 strcpy(parking_con_dial, "park-dial"); 03177 strcpy(parking_ext, "700"); 03178 strcpy(pickup_ext, "*8"); 03179 strcpy(parkmohclass, "default"); 03180 courtesytone[0] = '\0'; 03181 strcpy(xfersound, "beep"); 03182 strcpy(xferfailsound, "pbx-invalid"); 03183 parking_start = 701; 03184 parking_stop = 750; 03185 parkfindnext = 0; 03186 adsipark = 0; 03187 parkaddhints = 0; 03188 03189 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 03190 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 03191 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 03192 03193 cfg = ast_config_load("features.conf"); 03194 if (!cfg) { 03195 ast_log(LOG_WARNING,"Could not load features.conf\n"); 03196 return AST_MODULE_LOAD_DECLINE; 03197 } 03198 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { 03199 if (!strcasecmp(var->name, "parkext")) { 03200 ast_copy_string(parking_ext, var->value, sizeof(parking_ext)); 03201 } else if (!strcasecmp(var->name, "context")) { 03202 ast_copy_string(parking_con, var->value, sizeof(parking_con)); 03203 } else if (!strcasecmp(var->name, "parkingtime")) { 03204 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) { 03205 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value); 03206 parkingtime = DEFAULT_PARK_TIME; 03207 } else 03208 parkingtime = parkingtime * 1000; 03209 } else if (!strcasecmp(var->name, "parkpos")) { 03210 if (sscanf(var->value, "%d-%d", &start, &end) != 2) { 03211 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); 03212 } else { 03213 parking_start = start; 03214 parking_stop = end; 03215 } 03216 } else if (!strcasecmp(var->name, "findslot")) { 03217 parkfindnext = (!strcasecmp(var->value, "next")); 03218 } else if (!strcasecmp(var->name, "parkinghints")) { 03219 parkaddhints = ast_true(var->value); 03220 } else if (!strcasecmp(var->name, "adsipark")) { 03221 adsipark = ast_true(var->value); 03222 } else if (!strcasecmp(var->name, "transferdigittimeout")) { 03223 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) { 03224 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value); 03225 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 03226 } else 03227 transferdigittimeout = transferdigittimeout * 1000; 03228 } else if (!strcasecmp(var->name, "featuredigittimeout")) { 03229 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) { 03230 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value); 03231 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 03232 } 03233 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) { 03234 if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) { 03235 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value); 03236 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 03237 } else 03238 atxfernoanswertimeout = atxfernoanswertimeout * 1000; 03239 } else if (!strcasecmp(var->name, "courtesytone")) { 03240 ast_copy_string(courtesytone, var->value, sizeof(courtesytone)); 03241 } else if (!strcasecmp(var->name, "parkedplay")) { 03242 if (!strcasecmp(var->value, "both")) 03243 parkedplay = 2; 03244 else if (!strcasecmp(var->value, "parked")) 03245 parkedplay = 1; 03246 else 03247 parkedplay = 0; 03248 } else if (!strcasecmp(var->name, "xfersound")) { 03249 ast_copy_string(xfersound, var->value, sizeof(xfersound)); 03250 } else if (!strcasecmp(var->name, "xferfailsound")) { 03251 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound)); 03252 } else if (!strcasecmp(var->name, "pickupexten")) { 03253 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext)); 03254 } else if (!strcasecmp(var->name, "parkedmusicclass")) { 03255 ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass)); 03256 } 03257 } 03258 03259 unmap_features(); 03260 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) { 03261 if (remap_feature(var->name, var->value)) 03262 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); 03263 } 03264 03265 /* Map a key combination to an application*/ 03266 ast_unregister_features(); 03267 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) { 03268 char *tmp_val = ast_strdupa(var->value); 03269 char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 03270 struct ast_call_feature *feature; 03271 03272 /* strsep() sets the argument to NULL if match not found, and it 03273 * is safe to use it with a NULL argument, so we don't check 03274 * between calls. 03275 */ 03276 exten = strsep(&tmp_val,","); 03277 activatedby = strsep(&tmp_val,","); 03278 app = strsep(&tmp_val,","); 03279 app_args = strsep(&tmp_val,","); 03280 moh_class = strsep(&tmp_val,","); 03281 03282 activateon = strsep(&activatedby, "/"); 03283 03284 /*! \todo XXX var_name or app_args ? */ 03285 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) { 03286 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n", 03287 app, exten, activateon, var->name); 03288 continue; 03289 } 03290 03291 AST_LIST_LOCK(&feature_list); 03292 if ((feature = find_dynamic_feature(var->name))) { 03293 AST_LIST_UNLOCK(&feature_list); 03294 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name); 03295 continue; 03296 } 03297 AST_LIST_UNLOCK(&feature_list); 03298 03299 if (!(feature = ast_calloc(1, sizeof(*feature)))) 03300 continue; 03301 03302 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN); 03303 ast_copy_string(feature->app, app, FEATURE_APP_LEN); 03304 ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN); 03305 03306 if (app_args) 03307 ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN); 03308 03309 if (moh_class) 03310 ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN); 03311 03312 ast_copy_string(feature->exten, exten, sizeof(feature->exten)); 03313 feature->operation = feature_exec_app; 03314 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF); 03315 03316 /* Allow caller and calle to be specified for backwards compatability */ 03317 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) 03318 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF); 03319 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) 03320 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER); 03321 else { 03322 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s'," 03323 " must be 'self', or 'peer'\n", var->name); 03324 continue; 03325 } 03326 03327 if (ast_strlen_zero(activatedby)) 03328 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 03329 else if (!strcasecmp(activatedby, "caller")) 03330 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER); 03331 else if (!strcasecmp(activatedby, "callee")) 03332 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE); 03333 else if (!strcasecmp(activatedby, "both")) 03334 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 03335 else { 03336 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s'," 03337 " must be 'caller', or 'callee', or 'both'\n", var->name); 03338 continue; 03339 } 03340 03341 ast_register_feature(feature); 03342 03343 if (option_verbose >= 1) 03344 ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten); 03345 } 03346 ast_config_destroy(cfg); 03347 03348 /* Remove the old parking extension */ 03349 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) { 03350 if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar)) 03351 notify_metermaids(old_parking_ext, old_parking_con); 03352 if (option_debug) 03353 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con); 03354 } 03355 03356 if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) { 03357 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); 03358 return -1; 03359 } 03360 res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar); 03361 if (parkaddhints) 03362 park_add_hints(parking_con, parking_start, parking_stop); 03363 if (!res) 03364 notify_metermaids(ast_parking_ext(), parking_con); 03365 return res; 03366 03367 }
static int load_module | ( | void | ) | [static] |
Definition at line 3523 of file res_features.c.
References action_bridge(), 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(), bridge_exec(), do_autoanswer_thread(), do_holding_thread(), do_parking_thread(), EVENT_FLAG_CALL, EVENT_FLAG_COMMAND, load_config(), manager_park(), manager_parking_status(), metermaidstate(), park_call_exec(), park_exec(), and retrieve_call_exec().
03524 { 03525 int res; 03526 03527 ast_register_application(app_bridge, bridge_exec, bridge_synopsis, bridge_descrip); 03528 03529 memset(parking_ext, 0, sizeof(parking_ext)); 03530 memset(parking_con, 0, sizeof(parking_con)); 03531 03532 if ((res = load_config())) 03533 return res; 03534 ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); 03535 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL); 03536 ast_pthread_create(&holding_thread, NULL, do_holding_thread, NULL); 03537 res = ast_register_application(parkedcall, park_exec, synopsis, descrip); 03538 if (!res) 03539 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2); 03540 if (!res) { 03541 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" ); 03542 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park, 03543 "Park a channel", mandescr_park); 03544 ast_manager_register2("Bridge", EVENT_FLAG_COMMAND, action_bridge, "Bridge two channels already in the PBX", mandescr_bridge); 03545 } 03546 03547 res |= ast_register_application(holdedcall, retrieve_call_exec, synopsis, descrip); 03548 ast_pthread_create(&autoanswer_thread, NULL, do_autoanswer_thread, NULL); 03549 if (!res) 03550 res |= ast_register_application(autoanswerlogin, autoanswer_login_exec, synopsis3, descrip3); 03551 if (!res) 03552 res |= ast_register_application(autoanswer, autoanswer_exec, synopsis4, descrip4); 03553 03554 res |= ast_devstate_prov_add("Park", metermaidstate); 03555 03556 return res; 03557 }
static int manager_park | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 2633 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().
02634 { 02635 const char *channel = astman_get_header(m, "Channel"); 02636 const char *channel2 = astman_get_header(m, "Channel2"); 02637 const char *timeout = astman_get_header(m, "Timeout"); 02638 char buf[BUFSIZ]; 02639 int to = 0; 02640 int res = 0; 02641 int parkExt = 0; 02642 struct ast_channel *ch1, *ch2; 02643 02644 if (ast_strlen_zero(channel)) { 02645 astman_send_error(s, m, "Channel not specified"); 02646 return 0; 02647 } 02648 02649 if (ast_strlen_zero(channel2)) { 02650 astman_send_error(s, m, "Channel2 not specified"); 02651 return 0; 02652 } 02653 02654 ch1 = ast_get_channel_by_name_locked(channel); 02655 if (!ch1) { 02656 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel); 02657 astman_send_error(s, m, buf); 02658 return 0; 02659 } 02660 02661 ch2 = ast_get_channel_by_name_locked(channel2); 02662 if (!ch2) { 02663 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2); 02664 astman_send_error(s, m, buf); 02665 ast_channel_unlock(ch1); 02666 return 0; 02667 } 02668 02669 if (!ast_strlen_zero(timeout)) { 02670 sscanf(timeout, "%d", &to); 02671 } 02672 02673 res = ast_masq_park_call(ch1, ch2, to, &parkExt); 02674 if (!res) { 02675 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT); 02676 astman_send_ack(s, m, "Park successful"); 02677 } else { 02678 astman_send_error(s, m, "Park failure"); 02679 } 02680 02681 ast_channel_unlock(ch1); 02682 ast_channel_unlock(ch2); 02683 02684 return 0; 02685 }
static int manager_parking_status | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Dump lot status.
Definition at line 2585 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().
02586 { 02587 struct parkeduser *cur; 02588 const char *id = astman_get_header(m, "ActionID"); 02589 char idText[256] = ""; 02590 02591 if (!ast_strlen_zero(id)) 02592 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 02593 02594 astman_send_ack(s, m, "Parked calls will follow"); 02595 02596 ast_mutex_lock(&parking_lock); 02597 02598 for (cur = parkinglot; cur; cur = cur->next) { 02599 astman_append(s, "Event: ParkedCall\r\n" 02600 "Exten: %d\r\n" 02601 "Channel: %s\r\n" 02602 "From: %s\r\n" 02603 "Timeout: %ld\r\n" 02604 "CallerID: %s\r\n" 02605 "CallerIDName: %s\r\n" 02606 "Uniqueid: %s\r\n\r\n" 02607 "%s" 02608 "\r\n", 02609 cur->parkingnum, cur->chan->name, cur->peername, 02610 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL), 02611 S_OR(cur->chan->cid.cid_num, ""), /* XXX in other places it is <unknown> */ 02612 S_OR(cur->chan->cid.cid_name, ""), cur->chan->uniqueid, 02613 idText); 02614 } 02615 02616 astman_append(s, 02617 "Event: ParkedCallsComplete\r\n" 02618 "%s" 02619 "\r\n",idText); 02620 02621 ast_mutex_unlock(&parking_lock); 02622 02623 return RESULT_SUCCESS; 02624 }
static int metermaidstate | ( | const char * | data | ) | [static] |
metermaids callback from devicestate.c
Definition at line 372 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().
00373 { 00374 int res = AST_DEVICE_INVALID; 00375 char *context = ast_strdupa(data); 00376 char *exten; 00377 00378 exten = strsep(&context, "@"); 00379 if (!context) 00380 return res; 00381 00382 if (option_debug > 3) 00383 ast_log(LOG_DEBUG, "Checking state of exten %s in context %s\n", exten, context); 00384 00385 res = ast_exists_extension(NULL, context, exten, 1, NULL); 00386 00387 if (!res) 00388 return AST_DEVICE_NOT_INUSE; 00389 else 00390 return AST_DEVICE_INUSE; 00391 }
static void notify_metermaids | ( | char * | exten, | |
char * | context | |||
) | [static] |
Notify metermaids that we've changed an extension.
Definition at line 361 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().
00362 { 00363 if (option_debug > 3) 00364 ast_log(LOG_DEBUG, "Notification of state change to metermaids %s@%s\n", exten, context); 00365 00366 /* Send notification to devicestate subsystem */ 00367 ast_device_state_changed("park:%s@%s", exten, context); 00368 return; 00369 }
static void park_add_hints | ( | char * | context, | |
int | start, | |||
int | stop | |||
) | [static] |
Add parking hints for all defined parking lots.
Definition at line 3145 of file res_features.c.
References ast_add_extension(), AST_MAX_EXTENSION, exten, and PRIORITY_HINT.
Referenced by load_config().
03146 { 03147 int numext; 03148 char device[AST_MAX_EXTENSION]; 03149 char exten[10]; 03150 03151 for (numext = start; numext <= stop; numext++) { 03152 snprintf(exten, sizeof(exten), "%d", numext); 03153 snprintf(device, sizeof(device), "park:%s@%s", exten, context); 03154 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar); 03155 } 03156 }
static int park_call_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Park a call.
Definition at line 1930 of file res_features.c.
References ast_channel::_state, ast_answer(), AST_MAX_EXTENSION, ast_module_user_add, ast_module_user_remove, AST_PBX_KEEPALIVE, ast_safe_sleep(), AST_STATE_UP, ast_strdupa, ast_channel::exten, orig_exten(), park_call_full(), and ast_channel::priority.
Referenced by load_module().
01931 { 01932 /* Cache the original channel name in case we get masqueraded in the middle 01933 * of a park--it is still theoretically possible for a transfer to happen before 01934 * we get here, but it is _really_ unlikely */ 01935 char *orig_chan_name = ast_strdupa(chan->name); 01936 char orig_exten[AST_MAX_EXTENSION]; 01937 int orig_priority = chan->priority; 01938 01939 /* Data is unused at the moment but could contain a parking 01940 lot context eventually */ 01941 int res = 0; 01942 struct ast_module_user *u; 01943 01944 u = ast_module_user_add(chan); 01945 01946 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten)); 01947 01948 /* Setup the exten/priority to be s/1 since we don't know 01949 where this call should return */ 01950 strcpy(chan->exten, "s"); 01951 chan->priority = 1; 01952 /* Answer if call is not up */ 01953 if (chan->_state != AST_STATE_UP) 01954 res = ast_answer(chan); 01955 /* Sleep to allow VoIP streams to settle down */ 01956 if (!res) 01957 res = ast_safe_sleep(chan, 1000); 01958 /* Park the call */ 01959 if (!res) { 01960 res = park_call_full(chan, chan, 0, NULL, orig_chan_name); 01961 /* Continue on in the dialplan */ 01962 if (res == 1) { 01963 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten)); 01964 chan->priority = orig_priority; 01965 res = 0; 01966 } else if (!res) 01967 res = AST_PBX_KEEPALIVE; 01968 } 01969 01970 ast_module_user_remove(u); 01971 01972 return res; 01973 }
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 393 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_masq_park_call(), ast_park_call(), and park_call_exec().
00394 { 00395 struct parkeduser *pu, *cur; 00396 int i, x = -1, parking_range; 00397 struct ast_context *con; 00398 const char *parkingexten; 00399 00400 /* Allocate memory for parking data */ 00401 if (!(pu = ast_calloc(1, sizeof(*pu)))) 00402 return -1; 00403 00404 /* Lock parking lot */ 00405 ast_mutex_lock(&parking_lock); 00406 /* Check for channel variable PARKINGEXTEN */ 00407 parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN"); 00408 if (!ast_strlen_zero(parkingexten)) { 00409 if (ast_exists_extension(NULL, parking_con, parkingexten, 1, NULL)) { 00410 ast_mutex_unlock(&parking_lock); 00411 free(pu); 00412 ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con); 00413 return 1; /* Continue execution if possible */ 00414 } 00415 ast_copy_string(pu->parkingexten, parkingexten, sizeof(pu->parkingexten)); 00416 x = atoi(parkingexten); 00417 } else { 00418 /* Select parking space within range */ 00419 parking_range = parking_stop - parking_start+1; 00420 for (i = 0; i < parking_range; i++) { 00421 x = (i + parking_offset) % parking_range + parking_start; 00422 cur = parkinglot; 00423 while(cur) { 00424 if (cur->parkingnum == x) 00425 break; 00426 cur = cur->next; 00427 } 00428 if (!cur) 00429 break; 00430 } 00431 00432 if (!(i < parking_range)) { 00433 ast_log(LOG_WARNING, "No more parking spaces\n"); 00434 free(pu); 00435 ast_mutex_unlock(&parking_lock); 00436 return -1; 00437 } 00438 /* Set pointer for next parking */ 00439 if (parkfindnext) 00440 parking_offset = x - parking_start + 1; 00441 } 00442 00443 chan->appl = "Parked Call"; 00444 chan->data = NULL; 00445 00446 pu->chan = chan; 00447 00448 /* Put the parked channel on hold if we have two different channels */ 00449 if (chan != peer) { 00450 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 00451 S_OR(parkmohclass, NULL), 00452 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 00453 } 00454 00455 pu->start = ast_tvnow(); 00456 pu->parkingnum = x; 00457 pu->parkingtime = (timeout > 0) ? timeout : parkingtime; 00458 if (extout) 00459 *extout = x; 00460 00461 if (peer) 00462 ast_copy_string(pu->peername, peer->name, sizeof(pu->peername)); 00463 00464 /* Remember what had been dialed, so that if the parking 00465 expires, we try to come back to the same place */ 00466 ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context)); 00467 ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten)); 00468 pu->priority = chan->macropriority ? chan->macropriority : chan->priority; 00469 pu->next = parkinglot; 00470 parkinglot = pu; 00471 00472 /* If parking a channel directly, don't quiet yet get parking running on it */ 00473 if (peer == chan) 00474 pu->notquiteyet = 1; 00475 ast_mutex_unlock(&parking_lock); 00476 /* Wake up the (presumably select()ing) thread */ 00477 pthread_kill(parking_thread, SIGURG); 00478 if (option_verbose > 1) 00479 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)); 00480 00481 if (pu->parkingnum != -1) 00482 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x); 00483 manager_event(EVENT_FLAG_CALL, "ParkedCall", 00484 "Exten: %s\r\n" 00485 "Channel: %s\r\n" 00486 "From: %s\r\n" 00487 "Timeout: %ld\r\n" 00488 "CallerID: %s\r\n" 00489 "CallerIDName: %s\r\n" 00490 "Uniqueid: %s\r\n", 00491 pu->parkingexten, pu->chan->name, peer ? peer->name : "", 00492 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL), 00493 S_OR(pu->chan->cid.cid_num, "<unknown>"), 00494 S_OR(pu->chan->cid.cid_name, "<unknown>"), 00495 pu->chan->uniqueid 00496 ); 00497 00498 if (peer && adsipark && ast_adsi_available(peer)) { 00499 adsi_announce_park(peer, pu->parkingexten); /* Only supports parking numbers */ 00500 ast_adsi_unload_session(peer); 00501 } 00502 00503 con = ast_context_find(parking_con); 00504 if (!con) 00505 con = ast_context_create(NULL, parking_con, registrar); 00506 if (!con) /* Still no context? Bad */ 00507 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); 00508 /* Tell the peer channel the number of the parking space */ 00509 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 */ 00510 /* Make sure we don't start saying digits to the channel being parked */ 00511 ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM); 00512 ast_say_digits(peer, pu->parkingnum, "", peer->language); 00513 ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM); 00514 } 00515 if (con) { 00516 if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), ast_free, registrar)) 00517 notify_metermaids(pu->parkingexten, parking_con); 00518 } 00519 if (pu->notquiteyet) { 00520 /* Wake up parking thread if we're really done */ 00521 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 00522 S_OR(parkmohclass, NULL), 00523 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 00524 pu->notquiteyet = 0; 00525 pthread_kill(parking_thread, SIGURG); 00526 } 00527 return 0; 00528 }
static int park_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Pickup parked call.
Definition at line 1976 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().
01977 { 01978 int res = 0; 01979 struct ast_module_user *u; 01980 struct ast_channel *peer=NULL; 01981 struct parkeduser *pu, *pl=NULL; 01982 struct ast_context *con; 01983 01984 int park; 01985 struct ast_bridge_config config; 01986 01987 if (!data) { 01988 ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n"); 01989 return -1; 01990 } 01991 01992 u = ast_module_user_add(chan); 01993 01994 park = atoi((char *)data); 01995 ast_mutex_lock(&parking_lock); 01996 pu = parkinglot; 01997 while(pu) { 01998 if (pu->parkingnum == park) { 01999 if (pl) 02000 pl->next = pu->next; 02001 else 02002 parkinglot = pu->next; 02003 break; 02004 } 02005 pl = pu; 02006 pu = pu->next; 02007 } 02008 ast_mutex_unlock(&parking_lock); 02009 if (pu) { 02010 peer = pu->chan; 02011 con = ast_context_find(parking_con); 02012 if (con) { 02013 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL)) 02014 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 02015 else 02016 notify_metermaids(pu->parkingexten, parking_con); 02017 } else 02018 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 02019 02020 manager_event(EVENT_FLAG_CALL, "UnParkedCall", 02021 "Exten: %s\r\n" 02022 "Channel: %s\r\n" 02023 "From: %s\r\n" 02024 "CallerID: %s\r\n" 02025 "CallerIDName: %s\r\n" 02026 "Uniqueid: %s\r\n", 02027 pu->parkingexten, pu->chan->name, chan->name, 02028 S_OR(pu->chan->cid.cid_num, "<unknown>"), 02029 S_OR(pu->chan->cid.cid_name, "<unknown>"), 02030 pu->chan->uniqueid 02031 ); 02032 02033 free(pu); 02034 } 02035 /* JK02: it helps to answer the channel if not already up */ 02036 if (chan->_state != AST_STATE_UP) 02037 ast_answer(chan); 02038 02039 if (peer) { 02040 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */ 02041 02042 if (!ast_strlen_zero(courtesytone)) { 02043 int error = 0; 02044 ast_indicate(peer, AST_CONTROL_UNHOLD); 02045 if (parkedplay == 0) { 02046 error = ast_stream_and_wait(chan, courtesytone, chan->language, ""); 02047 } else if (parkedplay == 1) { 02048 error = ast_stream_and_wait(peer, courtesytone, chan->language, ""); 02049 } else if (parkedplay == 2) { 02050 if (!ast_streamfile(chan, courtesytone, chan->language) && 02051 !ast_streamfile(peer, courtesytone, chan->language)) { 02052 /*! \todo XXX we would like to wait on both! */ 02053 res = ast_waitstream(chan, ""); 02054 if (res >= 0) 02055 res = ast_waitstream(peer, ""); 02056 if (res < 0) 02057 error = 1; 02058 } 02059 } 02060 if (error) { 02061 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 02062 ast_hangup(peer); 02063 ast_module_user_remove(u); 02064 return -1; 02065 } 02066 } else 02067 ast_indicate(peer, AST_CONTROL_UNHOLD); 02068 02069 res = ast_channel_make_compatible(chan, peer); 02070 if (res < 0) { 02071 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); 02072 ast_hangup(peer); 02073 ast_module_user_remove(u); 02074 return -1; 02075 } 02076 /* This runs sorta backwards, since we give the incoming channel control, as if it 02077 were the person called. */ 02078 if (option_verbose > 2) 02079 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park); 02080 02081 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 02082 ast_cdr_setdestchan(chan->cdr, peer->name); 02083 memset(&config, 0, sizeof(struct ast_bridge_config)); 02084 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 02085 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 02086 res = ast_bridge_call(chan, peer, &config); 02087 02088 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 02089 ast_cdr_setdestchan(chan->cdr, peer->name); 02090 02091 /* Simulate the PBX hanging up */ 02092 if (res != AST_PBX_NO_HANGUP_PEER) 02093 ast_hangup(peer); 02094 ast_module_user_remove(u); 02095 return res; 02096 } else { 02097 /*! \todo XXX Play a message XXX */ 02098 if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, "")) 02099 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name); 02100 if (option_verbose > 2) 02101 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park); 02102 res = -1; 02103 } 02104 02105 ast_module_user_remove(u); 02106 02107 return res; 02108 }
static void post_manager_event | ( | const char * | s, | |
char * | parkingexten, | |||
struct ast_channel * | chan | |||
) | [static] |
Definition at line 1745 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().
01746 { 01747 manager_event(EVENT_FLAG_CALL, s, 01748 "Exten: %s\r\n" 01749 "Channel: %s\r\n" 01750 "CallerID: %s\r\n" 01751 "CallerIDName: %s\r\n" 01752 "Uniqueid: %s\r\n\r\n", 01753 parkingexten, 01754 chan->name, 01755 S_OR(chan->cid.cid_num, "<unknown>"), 01756 S_OR(chan->cid.cid_name, "<unknown>"), 01757 chan->uniqueid 01758 ); 01759 }
static const char* real_ctx | ( | struct ast_channel * | transferer, | |
struct ast_channel * | transferee | |||
) | [static] |
Find the context for the transfer.
Definition at line 731 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().
00732 { 00733 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"); 00734 if (ast_strlen_zero(s)) 00735 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT"); 00736 if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */ 00737 s = transferer->macrocontext; 00738 if (ast_strlen_zero(s)) 00739 s = transferer->context; 00740 return s; 00741 }
static int reload | ( | void | ) | [static] |
Definition at line 3517 of file res_features.c.
References autoanswer_reregister_extensions(), and load_config().
03518 { 03519 autoanswer_reregister_extensions(); 03520 return load_config(); 03521 }
static int remap_feature | ( | const char * | name, | |
const char * | value | |||
) | [static] |
Definition at line 1129 of file res_features.c.
References ast_rwlock_unlock(), ast_rwlock_wrlock(), exten, and FEATURES_COUNT.
Referenced by load_config().
01130 { 01131 int x, res = -1; 01132 01133 ast_rwlock_wrlock(&features_lock); 01134 for (x = 0; x < FEATURES_COUNT; x++) { 01135 if (strcasecmp(builtin_features[x].sname, name)) 01136 continue; 01137 01138 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten)); 01139 res = 0; 01140 break; 01141 } 01142 ast_rwlock_unlock(&features_lock); 01143 01144 return res; 01145 }
static int retrieve_call_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 2376 of file res_features.c.
References ast_module_user_add, ast_module_user_remove, and ast_retrieve_call().
Referenced by load_module().
02376 { 02377 int res=0; 02378 struct ast_module_user *u; 02379 char *uniqueid = (char *)data; 02380 u = ast_module_user_add(chan); 02381 res = ast_retrieve_call(chan, uniqueid); 02382 ast_module_user_remove(u); 02383 return res; 02384 }
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 239 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().
00240 { 00241 ast_copy_string(chan->context, context, sizeof(chan->context)); 00242 ast_copy_string(chan->exten, ext, sizeof(chan->exten)); 00243 chan->priority = pri; 00244 }
static void set_config_flags | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config | |||
) | [static] |
Definition at line 1213 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().
01214 { 01215 int x; 01216 01217 ast_clear_flag(config, AST_FLAGS_ALL); 01218 01219 ast_rwlock_rdlock(&features_lock); 01220 for (x = 0; x < FEATURES_COUNT; x++) { 01221 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) 01222 continue; 01223 01224 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask)) 01225 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 01226 01227 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask)) 01228 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 01229 } 01230 ast_rwlock_unlock(&features_lock); 01231 01232 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) { 01233 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"); 01234 01235 if (dynamic_features) { 01236 char *tmp = ast_strdupa(dynamic_features); 01237 char *tok; 01238 struct ast_call_feature *feature; 01239 01240 /* while we have a feature */ 01241 while ((tok = strsep(&tmp, "#"))) { 01242 AST_LIST_LOCK(&feature_list); 01243 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) { 01244 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 01245 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 01246 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 01247 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 01248 } 01249 AST_LIST_UNLOCK(&feature_list); 01250 } 01251 } 01252 } 01253 }
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 586 of file res_features.c.
References FEATURE_SENSE_PEER.
Referenced by builtin_atxfer(), builtin_automonitor(), builtin_blindtransfer(), and builtin_parkcall().
00588 { 00589 if (sense == FEATURE_SENSE_PEER) { 00590 *caller = peer; 00591 *callee = chan; 00592 } else { 00593 *callee = peer; 00594 *caller = chan; 00595 } 00596 }
static int unload_module | ( | void | ) | [static] |
Definition at line 3560 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().
03561 { 03562 ast_module_user_hangup_all(); 03563 03564 ast_manager_unregister("ParkedCalls"); 03565 ast_manager_unregister("Bridge"); 03566 ast_manager_unregister("Park"); 03567 ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); 03568 ast_unregister_application(parkcall); 03569 ast_unregister_application(app_bridge); 03570 ast_unregister_application(autoanswer); 03571 ast_unregister_application(autoanswerlogin); 03572 ast_unregister_application(holdedcall); 03573 ast_devstate_prov_del("Park"); 03574 return ast_unregister_application(parkedcall); 03575 }
static void unmap_features | ( | void | ) | [static] |
Definition at line 1119 of file res_features.c.
References ast_rwlock_unlock(), ast_rwlock_wrlock(), exten, and FEATURES_COUNT.
Referenced by load_config().
01120 { 01121 int x; 01122 01123 ast_rwlock_wrlock(&features_lock); 01124 for (x = 0; x < FEATURES_COUNT; x++) 01125 strcpy(builtin_features[x].exten, builtin_features[x].default_exten); 01126 ast_rwlock_unlock(&features_lock); 01127 }
Definition at line 202 of file res_features.c.
int adsipark [static] |
Definition at line 108 of file res_features.c.
char* app_bridge = "Bridge" [static] |
Definition at line 3369 of file res_features.c.
int atxfernoanswertimeout [static] |
Definition at line 113 of file res_features.c.
char* autoanswer = "Autoanswer" [static] |
Definition at line 148 of file res_features.c.
pthread_t autoanswer_thread [static] |
Definition at line 204 of file res_features.c.
char* autoanswerlogin = "AutoanswerLogin" [static] |
Definition at line 141 of file res_features.c.
char* bridge_descrip [static] |
Definition at line 3371 of file res_features.c.
char* bridge_synopsis = "Bridge two channels" [static] |
Definition at line 3370 of file res_features.c.
struct ast_call_feature builtin_features[] [static] |
Definition at line 993 of file res_features.c.
struct ast_cli_entry cli_features[] [static] |
Definition at line 2708 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 2574 of file res_features.c.
char courtesytone[256] [static] |
Courtesy tone
Definition at line 100 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 120 of file res_features.c.
char* descrip2 [static] |
Definition at line 130 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 145 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 152 of file res_features.c.
int featuredigittimeout [static] |
Definition at line 111 of file res_features.c.
char* holdedcall = "HoldedCall" [static] |
Definition at line 88 of file res_features.c.
pthread_t holding_thread [static] |
Definition at line 216 of file res_features.c.
struct holdeduser* holdlist [static] |
Definition at line 208 of file res_features.c.
char mandescr_bridge[] [static] |
Definition at line 2423 of file res_features.c.
char mandescr_park[] [static] |
Definition at line 2626 of file res_features.c.
struct ast_app* monitor_app = NULL [static] |
Definition at line 155 of file res_features.c.
int monitor_ok = 1 [static] |
Definition at line 156 of file res_features.c.
int parkaddhints = 0 [static] |
Add parking hints automatically
Definition at line 90 of file res_features.c.
char* parkcall = "Park" [static] |
Definition at line 126 of file res_features.c.
char* parkedcall = "ParkedCall" [static] |
Definition at line 87 of file res_features.c.
int parkedplay = 0 [static] |
Who to play the courtesy tone to
Definition at line 101 of file res_features.c.
int parkfindnext [static] |
Definition at line 106 of file res_features.c.
char parking_con[AST_MAX_EXTENSION] [static] |
Context for which parking is made accessible
Definition at line 92 of file res_features.c.
char parking_con_dial[AST_MAX_EXTENSION] [static] |
Context for dialback for parking (KLUDGE)
Definition at line 93 of file res_features.c.
char parking_ext[AST_MAX_EXTENSION] [static] |
Extension you type to park the call
Definition at line 94 of file res_features.c.
int parking_offset [static] |
Definition at line 105 of file res_features.c.
int parking_start [static] |
First available extension for parking
Definition at line 97 of file res_features.c.
int parking_stop [static] |
Last available extension for parking
Definition at line 98 of file res_features.c.
pthread_t parking_thread [static] |
Definition at line 214 of file res_features.c.
struct parkeduser* parkinglot [static] |
Definition at line 206 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 91 of file res_features.c.
char parkmohclass[MAX_MUSICCLASS] [static] |
Music class used for parking
Definition at line 96 of file res_features.c.
char pickup_ext[AST_MAX_EXTENSION] [static] |
Call pickup extension
Definition at line 95 of file res_features.c.
char* registrar = "res_features" [static] |
Registrar for operations
Definition at line 115 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 2579 of file res_features.c.
char showfeatures_help[] [static] |
Initial value:
"Usage: feature list\n" " Lists currently configured features.\n"
Definition at line 2542 of file res_features.c.
char showparked_help[] [static] |
Initial value:
"Usage: show parkedcalls\n" " Lists currently parked calls.\n"
Definition at line 2570 of file res_features.c.
char* synopsis = "Answer a parked call" [static] |
Definition at line 118 of file res_features.c.
char* synopsis2 = "Park yourself" [static] |
Definition at line 128 of file res_features.c.
char* synopsis3 = "Log in for autoanswer" [static] |
Definition at line 143 of file res_features.c.
char* synopsis4 = "Autoanswer a call" [static] |
Definition at line 150 of file res_features.c.
int transferdigittimeout [static] |
Definition at line 110 of file res_features.c.
char xferfailsound[256] [static] |
Call transfer failure sound
Definition at line 103 of file res_features.c.
char xfersound[256] [static] |
Call transfer sound
Definition at line 102 of file res_features.c.