#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 dependency graph for res_features.c:
Go to the source code of this file.
Data Structures | |
struct | ast_bridge_thread_obj |
struct | parkeduser |
Defines | |
#define | AST_MAX_WATCHERS 256 |
#define | DEFAULT_FEATURE_DIGIT_TIMEOUT 500 |
#define | DEFAULT_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_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) |
static | AST_LIST_HEAD_STATIC (feature_list, ast_call_feature) |
int | ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout) |
Park a call via a masqueraded channel. | |
AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS,"Call Features Resource",.load=load_module,.unload=unload_module,.reload=reload,) | |
AST_MUTEX_DEFINE_STATIC (parking_lock) | |
int | ast_park_call (struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout) |
Park a call and read back parked location. | |
char * | ast_parking_ext (void) |
Determine system parking extension Returns the call parking extension for drivers that provide special call parking help. | |
int | ast_pickup_call (struct ast_channel *chan) |
Pickup a call. | |
char * | ast_pickup_ext (void) |
Determine system call pickup extension. | |
void | ast_register_feature (struct ast_call_feature *feature) |
register new feature into feature_set | |
AST_RWLOCK_DEFINE_STATIC (features_lock) | |
void | ast_unregister_feature (struct ast_call_feature *feature) |
unregister feature from feature_set | |
static void | ast_unregister_features (void) |
Remove all features in the list. | |
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_bridge_masquerade (struct ast_channel *chan, struct ast_channel *tmpchan) |
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_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 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 int | adsipark |
static char * | app_bridge = "Bridge" |
static int | atxfernoanswertimeout |
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 int | featuredigittimeout |
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 | showfeatures_help [] |
static char | showparked_help [] |
static char * | synopsis = "Answer a parked call" |
static char * | synopsis2 = "Park yourself" |
static int | transferdigittimeout |
static char | xferfailsound [256] |
static char | xfersound [256] |
Definition in file res_features.c.
#define AST_MAX_WATCHERS 256 |
Definition at line 71 of file res_features.c.
#define DEFAULT_FEATURE_DIGIT_TIMEOUT 500 |
#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000 |
#define DEFAULT_PARK_TIME 45000 |
Definition at line 66 of file res_features.c.
#define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 |
#define FEATURE_RETURN_HANGUP -1 |
#define FEATURE_RETURN_KEEPTRYING 24 |
Definition at line 517 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 514 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 516 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 519 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 928 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 73 of file res_features.c.
00073 { 00074 AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0), 00075 AST_FEATURE_FLAG_ONPEER = (1 << 1), 00076 AST_FEATURE_FLAG_ONSELF = (1 << 2), 00077 AST_FEATURE_FLAG_BYCALLEE = (1 << 3), 00078 AST_FEATURE_FLAG_BYCALLER = (1 << 4), 00079 AST_FEATURE_FLAG_BYBOTH = (3 << 3), 00080 };
anonymous enum |
Definition at line 2594 of file res_features.c.
02594 { 02595 BRIDGE_OPT_PLAYTONE = (1 << 0), 02596 };
static int action_bridge | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 2079 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(), do_bridge_masquerade(), errno, ast_channel::lock, LOG_WARNING, playtone(), s, and xfersound.
Referenced by load_module().
02080 { 02081 const char *channela = astman_get_header(m, "Channel1"); 02082 const char *channelb = astman_get_header(m, "Channel2"); 02083 const char *playtone = astman_get_header(m, "Tone"); 02084 struct ast_channel *chana = NULL, *chanb = NULL; 02085 struct ast_channel *tmpchana = NULL, *tmpchanb = NULL; 02086 struct ast_bridge_thread_obj *tobj = NULL; 02087 02088 /* make sure valid channels were specified */ 02089 if (!ast_strlen_zero(channela) && !ast_strlen_zero(channelb)) { 02090 chana = ast_get_channel_by_name_prefix_locked(channela, strlen(channela)); 02091 chanb = ast_get_channel_by_name_prefix_locked(channelb, strlen(channelb)); 02092 if (chana) 02093 ast_mutex_unlock(&chana->lock); 02094 if (chanb) 02095 ast_mutex_unlock(&chanb->lock); 02096 02097 /* send errors if any of the channels could not be found/locked */ 02098 if (!chana) { 02099 char buf[256]; 02100 snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela); 02101 astman_send_error(s, m, buf); 02102 return 0; 02103 } 02104 if (!chanb) { 02105 char buf[256]; 02106 snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb); 02107 astman_send_error(s, m, buf); 02108 return 0; 02109 } 02110 } else { 02111 astman_send_error(s, m, "Missing channel parameter in request"); 02112 return 0; 02113 } 02114 02115 /* Answer the channels if needed */ 02116 if (chana->_state != AST_STATE_UP) 02117 ast_answer(chana); 02118 if (chanb->_state != AST_STATE_UP) 02119 ast_answer(chanb); 02120 02121 /* create the placeholder channels and grab the other channels */ 02122 if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 02123 NULL, NULL, 0, "Bridge/%s", chana->name))) { 02124 astman_send_error(s, m, "Unable to create temporary channel!"); 02125 return 1; 02126 } 02127 02128 if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 02129 NULL, NULL, 0, "Bridge/%s", chanb->name))) { 02130 astman_send_error(s, m, "Unable to create temporary channels!"); 02131 ast_channel_free(tmpchana); 02132 return 1; 02133 } 02134 02135 do_bridge_masquerade(chana, tmpchana); 02136 do_bridge_masquerade(chanb, tmpchanb); 02137 02138 /* make the channels compatible, send error if we fail doing so */ 02139 if (ast_channel_make_compatible(tmpchana, tmpchanb)) { 02140 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name); 02141 astman_send_error(s, m, "Could not make channels compatible for manager bridge"); 02142 ast_hangup(tmpchana); 02143 ast_hangup(tmpchanb); 02144 return 1; 02145 } 02146 02147 /* setup the bridge thread object and start the bridge */ 02148 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) { 02149 ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno)); 02150 astman_send_error(s, m, "Unable to spawn a new bridge thread"); 02151 ast_hangup(tmpchana); 02152 ast_hangup(tmpchanb); 02153 return 1; 02154 } 02155 02156 tobj->chan = tmpchana; 02157 tobj->peer = tmpchanb; 02158 tobj->return_to_pbx = 1; 02159 02160 if (ast_true(playtone)) { 02161 if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) { 02162 if (ast_waitstream(tmpchanb, "") < 0) 02163 ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name); 02164 } 02165 } 02166 02167 ast_bridge_call_thread_launch(tobj); 02168 02169 astman_send_ack(s, m, "Launched bridge thread with success"); 02170 02171 return 0; 02172 }
static int adsi_announce_park | ( | struct ast_channel * | chan, | |
char * | parkingexten | |||
) | [static] |
Definition at line 286 of file res_features.c.
References ADSI_JUST_CENT, ast_adsi_load_session(), ast_adsi_print(), and justify.
Referenced by park_call_full().
00287 { 00288 int res; 00289 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT}; 00290 char tmp[256]; 00291 char *message[5] = {NULL, NULL, NULL, NULL, NULL}; 00292 00293 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten); 00294 message[0] = tmp; 00295 res = ast_adsi_load_session(chan, NULL, 0, 1); 00296 if (res == -1) 00297 return res; 00298 return ast_adsi_print(chan, message, justify, 1); 00299 }
AST_APP_OPTIONS | ( | bridge_exec_options | , | |
BEGIN_OPTIONS | END_OPTIONS | |||
) |
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 1376 of file res_features.c.
References ast_channel::appl, ast_answer(), ast_cdr_alloc(), ast_cdr_appenduserfield(), ast_cdr_discard(), AST_CDR_FLAG_LOCKED, ast_cdr_init(), ast_cdr_merge(), ast_cdr_setdestchan(), ast_cdr_setuserfield(), ast_cdr_start(), ast_channel_bridge(), ast_channel_setoption(), ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OPTION, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_dtmf_stream(), ast_feature_interpret(), AST_FEATURE_PLAY_WARNING, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, ast_frfree, ast_indicate(), ast_indicate_data(), ast_log(), AST_OPTION_FLAG_REQUEST, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_channel::cdr, ast_cdr::channel, config, ast_option_header::data, ast_channel::data, ast_cdr::dstchannel, f, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_option_header::flag, free, LOG_DEBUG, LOG_WARNING, monitor_app, ast_option_header::option, option_debug, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), set_config_flags(), and ast_cdr::userfield.
Referenced by app_exec(), ast_bridge_call_thread(), bridge_exec(), builtin_atxfer(), park_exec(), and try_calling().
01377 { 01378 /* Copy voice back and forth between the two channels. Give the peer 01379 the ability to transfer calls with '#<extension' syntax. */ 01380 struct ast_frame *f; 01381 struct ast_channel *who; 01382 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 01383 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 01384 int res; 01385 int diff; 01386 int hasfeatures=0; 01387 int hadfeatures=0; 01388 struct ast_option_header *aoh; 01389 struct ast_bridge_config backup_config; 01390 struct ast_cdr *bridge_cdr; 01391 01392 memset(&backup_config, 0, sizeof(backup_config)); 01393 01394 config->start_time = ast_tvnow(); 01395 01396 if (chan && peer) { 01397 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 01398 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 01399 } else if (chan) 01400 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 01401 01402 if (monitor_ok) { 01403 const char *monitor_exec; 01404 struct ast_channel *src = NULL; 01405 if (!monitor_app) { 01406 if (!(monitor_app = pbx_findapp("Monitor"))) 01407 monitor_ok=0; 01408 } 01409 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 01410 src = chan; 01411 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 01412 src = peer; 01413 if (monitor_app && src) { 01414 char *tmp = ast_strdupa(monitor_exec); 01415 pbx_exec(src, monitor_app, tmp); 01416 } 01417 } 01418 01419 set_config_flags(chan, peer, config); 01420 config->firstpass = 1; 01421 01422 /* Answer if need be */ 01423 if (ast_answer(chan)) 01424 return -1; 01425 peer->appl = "Bridged Call"; 01426 peer->data = chan->name; 01427 01428 /* copy the userfield from the B-leg to A-leg if applicable */ 01429 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) { 01430 char tmp[256]; 01431 if (!ast_strlen_zero(chan->cdr->userfield)) { 01432 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield); 01433 ast_cdr_appenduserfield(chan, tmp); 01434 } else 01435 ast_cdr_setuserfield(chan, peer->cdr->userfield); 01436 /* free the peer's cdr without ast_cdr_free complaining */ 01437 free(peer->cdr); 01438 peer->cdr = NULL; 01439 } 01440 01441 for (;;) { 01442 struct ast_channel *other; /* used later */ 01443 01444 res = ast_channel_bridge(chan, peer, config, &f, &who); 01445 01446 if (config->feature_timer) { 01447 /* Update time limit for next pass */ 01448 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time); 01449 config->feature_timer -= diff; 01450 if (hasfeatures) { 01451 /* Running on backup config, meaning a feature might be being 01452 activated, but that's no excuse to keep things going 01453 indefinitely! */ 01454 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) { 01455 if (option_debug) 01456 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n"); 01457 config->feature_timer = 0; 01458 who = chan; 01459 if (f) 01460 ast_frfree(f); 01461 f = NULL; 01462 res = 0; 01463 } else if (config->feature_timer <= 0) { 01464 /* Not *really* out of time, just out of time for 01465 digits to come in for features. */ 01466 if (option_debug) 01467 ast_log(LOG_DEBUG, "Timed out for feature!\n"); 01468 if (!ast_strlen_zero(peer_featurecode)) { 01469 ast_dtmf_stream(chan, peer, peer_featurecode, 0); 01470 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 01471 } 01472 if (!ast_strlen_zero(chan_featurecode)) { 01473 ast_dtmf_stream(peer, chan, chan_featurecode, 0); 01474 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 01475 } 01476 if (f) 01477 ast_frfree(f); 01478 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01479 if (!hasfeatures) { 01480 /* Restore original (possibly time modified) bridge config */ 01481 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01482 memset(&backup_config, 0, sizeof(backup_config)); 01483 } 01484 hadfeatures = hasfeatures; 01485 /* Continue as we were */ 01486 continue; 01487 } else if (!f) { 01488 /* The bridge returned without a frame and there is a feature in progress. 01489 * However, we don't think the feature has quite yet timed out, so just 01490 * go back into the bridge. */ 01491 continue; 01492 } 01493 } else { 01494 if (config->feature_timer <=0) { 01495 /* We ran out of time */ 01496 config->feature_timer = 0; 01497 who = chan; 01498 if (f) 01499 ast_frfree(f); 01500 f = NULL; 01501 res = 0; 01502 } 01503 } 01504 } 01505 if (res < 0) { 01506 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) 01507 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 01508 return -1; 01509 } 01510 01511 if (!f || (f->frametype == AST_FRAME_CONTROL && 01512 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 01513 f->subclass == AST_CONTROL_CONGESTION))) { 01514 res = -1; 01515 break; 01516 } 01517 /* many things should be sent to the 'other' channel */ 01518 other = (who == chan) ? peer : chan; 01519 if (f->frametype == AST_FRAME_CONTROL) { 01520 switch (f->subclass) { 01521 case AST_CONTROL_RINGING: 01522 case AST_CONTROL_FLASH: 01523 case -1: 01524 ast_indicate(other, f->subclass); 01525 break; 01526 case AST_CONTROL_HOLD: 01527 case AST_CONTROL_UNHOLD: 01528 ast_indicate_data(other, f->subclass, f->data, f->datalen); 01529 break; 01530 case AST_CONTROL_OPTION: 01531 aoh = f->data; 01532 /* Forward option Requests */ 01533 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 01534 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 01535 f->datalen - sizeof(struct ast_option_header), 0); 01536 } 01537 break; 01538 } 01539 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 01540 /* eat it */ 01541 } else if (f->frametype == AST_FRAME_DTMF) { 01542 char *featurecode; 01543 int sense; 01544 01545 hadfeatures = hasfeatures; 01546 /* This cannot overrun because the longest feature is one shorter than our buffer */ 01547 if (who == chan) { 01548 sense = FEATURE_SENSE_CHAN; 01549 featurecode = chan_featurecode; 01550 } else { 01551 sense = FEATURE_SENSE_PEER; 01552 featurecode = peer_featurecode; 01553 } 01554 /*! append the event to featurecode. we rely on the string being zero-filled, and 01555 * not overflowing it. 01556 * \todo XXX how do we guarantee the latter ? 01557 */ 01558 featurecode[strlen(featurecode)] = f->subclass; 01559 /* Get rid of the frame before we start doing "stuff" with the channels */ 01560 ast_frfree(f); 01561 f = NULL; 01562 config->feature_timer = backup_config.feature_timer; 01563 res = ast_feature_interpret(chan, peer, config, featurecode, sense); 01564 switch(res) { 01565 case FEATURE_RETURN_PASSDIGITS: 01566 ast_dtmf_stream(other, who, featurecode, 0); 01567 /* Fall through */ 01568 case FEATURE_RETURN_SUCCESS: 01569 memset(featurecode, 0, sizeof(chan_featurecode)); 01570 break; 01571 } 01572 if (res >= FEATURE_RETURN_PASSDIGITS) { 01573 res = 0; 01574 } else 01575 break; 01576 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01577 if (hadfeatures && !hasfeatures) { 01578 /* Restore backup */ 01579 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01580 memset(&backup_config, 0, sizeof(struct ast_bridge_config)); 01581 } else if (hasfeatures) { 01582 if (!hadfeatures) { 01583 /* Backup configuration */ 01584 memcpy(&backup_config, config, sizeof(struct ast_bridge_config)); 01585 /* Setup temporary config options */ 01586 config->play_warning = 0; 01587 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 01588 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 01589 config->warning_freq = 0; 01590 config->warning_sound = NULL; 01591 config->end_sound = NULL; 01592 config->start_sound = NULL; 01593 config->firstpass = 0; 01594 } 01595 config->start_time = ast_tvnow(); 01596 config->feature_timer = featuredigittimeout; 01597 if (option_debug) 01598 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer); 01599 } 01600 } 01601 if (f) 01602 ast_frfree(f); 01603 01604 } 01605 01606 /* arrange the cdrs */ 01607 bridge_cdr = ast_cdr_alloc(); 01608 if (bridge_cdr) { 01609 if (chan->cdr && peer->cdr) { /* both of them? merge */ 01610 ast_cdr_init(bridge_cdr,chan); /* seems more logicaller to use the destination as a base, but, really, it's random */ 01611 ast_cdr_start(bridge_cdr); /* now is the time to start */ 01612 01613 /* absorb the channel cdr */ 01614 ast_cdr_merge(bridge_cdr, chan->cdr); 01615 if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED)) 01616 ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */ 01617 01618 /* absorb the peer cdr */ 01619 ast_cdr_merge(bridge_cdr, peer->cdr); 01620 if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED)) 01621 ast_cdr_discard(peer->cdr); /* if locked cdrs are in peer, they are taken over in the merge */ 01622 01623 peer->cdr = NULL; 01624 chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */ 01625 } else if (chan->cdr) { 01626 /* take the cdr from the channel - literally */ 01627 ast_cdr_init(bridge_cdr,chan); 01628 /* absorb this data */ 01629 ast_cdr_merge(bridge_cdr, chan->cdr); 01630 if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED)) 01631 ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */ 01632 chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */ 01633 } else if (peer->cdr) { 01634 /* take the cdr from the peer - literally */ 01635 ast_cdr_init(bridge_cdr,peer); 01636 /* absorb this data */ 01637 ast_cdr_merge(bridge_cdr, peer->cdr); 01638 if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED)) 01639 ast_cdr_discard(peer->cdr); /* if locked cdrs are in chan, they are taken over in the merge */ 01640 peer->cdr = NULL; 01641 peer->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */ 01642 } else { 01643 /* make up a new cdr */ 01644 ast_cdr_init(bridge_cdr,chan); /* eh, just pick one of them */ 01645 chan->cdr = bridge_cdr; /* */ 01646 } 01647 if (ast_strlen_zero(bridge_cdr->dstchannel)) { 01648 if (strcmp(bridge_cdr->channel, peer->name) != 0) 01649 ast_cdr_setdestchan(bridge_cdr, peer->name); 01650 else 01651 ast_cdr_setdestchan(bridge_cdr, chan->name); 01652 } 01653 } 01654 return res; 01655 }
static void* ast_bridge_call_thread | ( | void * | data | ) | [static] |
Definition at line 226 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().
00227 { 00228 struct ast_bridge_thread_obj *tobj = data; 00229 int res; 00230 00231 tobj->chan->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge"; 00232 tobj->chan->data = tobj->peer->name; 00233 tobj->peer->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge"; 00234 tobj->peer->data = tobj->chan->name; 00235 00236 if (tobj->chan->cdr) { 00237 ast_cdr_reset(tobj->chan->cdr, NULL); 00238 ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name); 00239 } 00240 if (tobj->peer->cdr) { 00241 ast_cdr_reset(tobj->peer->cdr, NULL); 00242 ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name); 00243 } 00244 00245 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig); 00246 00247 if (tobj->return_to_pbx) { 00248 if (!ast_check_hangup(tobj->peer)) { 00249 ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", tobj->peer->name); 00250 res = ast_pbx_start(tobj->peer); 00251 if (res != AST_PBX_SUCCESS) 00252 ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", tobj->peer->name); 00253 } else 00254 ast_hangup(tobj->peer); 00255 if (!ast_check_hangup(tobj->chan)) { 00256 ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", tobj->chan->name); 00257 res = ast_pbx_start(tobj->chan); 00258 if (res != AST_PBX_SUCCESS) 00259 ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", tobj->chan->name); 00260 } else 00261 ast_hangup(tobj->chan); 00262 } else { 00263 ast_hangup(tobj->chan); 00264 ast_hangup(tobj->peer); 00265 } 00266 00267 free(tobj); 00268 00269 return NULL; 00270 }
static void ast_bridge_call_thread_launch | ( | void * | data | ) | [static] |
Definition at line 272 of file res_features.c.
References ast_bridge_call_thread(), ast_pthread_create, and thread.
Referenced by action_bridge(), and builtin_atxfer().
00273 { 00274 pthread_t thread; 00275 pthread_attr_t attr; 00276 struct sched_param sched; 00277 00278 pthread_attr_init(&attr); 00279 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 00280 ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data); 00281 pthread_attr_destroy(&attr); 00282 memset(&sched, 0, sizeof(sched)); 00283 pthread_setschedparam(thread, SCHED_RR, &sched); 00284 }
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 1086 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(), builtin_features, config, ast_call_feature::exten, exten, ast_call_feature::feature_mask, FEATURE_RETURN_KEEPTRYING, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_STOREDIGITS, FEATURE_SENSE_CHAN, 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().
01087 { 01088 int x; 01089 struct ast_flags features; 01090 int res = FEATURE_RETURN_PASSDIGITS; 01091 struct ast_call_feature *feature; 01092 const char *dynamic_features; 01093 char *tmp, *tok; 01094 01095 if (sense == FEATURE_SENSE_CHAN) { 01096 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL); 01097 dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"); 01098 } else { 01099 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL); 01100 dynamic_features = pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"); 01101 } 01102 if (option_debug > 2) 01103 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); 01104 01105 ast_rwlock_rdlock(&features_lock); 01106 for (x = 0; x < FEATURES_COUNT; x++) { 01107 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) && 01108 !ast_strlen_zero(builtin_features[x].exten)) { 01109 /* Feature is up for consideration */ 01110 if (!strcmp(builtin_features[x].exten, code)) { 01111 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL); 01112 break; 01113 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) { 01114 if (res == FEATURE_RETURN_PASSDIGITS) 01115 res = FEATURE_RETURN_STOREDIGITS; 01116 } 01117 } 01118 } 01119 ast_rwlock_unlock(&features_lock); 01120 01121 if (ast_strlen_zero(dynamic_features)) 01122 return res; 01123 01124 tmp = ast_strdupa(dynamic_features); 01125 01126 while ((tok = strsep(&tmp, "#"))) { 01127 AST_LIST_LOCK(&feature_list); 01128 if (!(feature = find_dynamic_feature(tok))) { 01129 AST_LIST_UNLOCK(&feature_list); 01130 continue; 01131 } 01132 01133 /* Feature is up for consideration */ 01134 if (!strcmp(feature->exten, code)) { 01135 if (option_verbose > 2) 01136 ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok); 01137 res = feature->operation(chan, peer, config, code, sense, feature); 01138 if (res != FEATURE_RETURN_KEEPTRYING) { 01139 AST_LIST_UNLOCK(&feature_list); 01140 break; 01141 } 01142 res = FEATURE_RETURN_PASSDIGITS; 01143 } else if (!strncmp(feature->exten, code, strlen(code))) 01144 res = FEATURE_RETURN_STOREDIGITS; 01145 01146 AST_LIST_UNLOCK(&feature_list); 01147 } 01148 01149 return res; 01150 }
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] |
Definition at line 1195 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(), builtin_features, ast_channel::cdr, ast_call_feature::exten, f, FEATURES_COUNT, ast_channel::hangupcause, len, LOG_NOTICE, LOG_WARNING, option_verbose, pbx_builtin_setvar_helper(), and VERBOSE_PREFIX_3.
Referenced by builtin_atxfer().
01196 { 01197 int state = 0; 01198 int cause = 0; 01199 int to; 01200 struct ast_channel *chan; 01201 struct ast_channel *monitor_chans[2]; 01202 struct ast_channel *active_channel; 01203 int res = 0, ready = 0; 01204 01205 if ((chan = ast_request(type, format, data, &cause))) { 01206 ast_set_callerid(chan, cid_num, cid_name, cid_num); 01207 ast_string_field_set(chan, language, language); 01208 ast_channel_inherit_variables(caller, chan); 01209 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name); 01210 if (!chan->cdr) { 01211 chan->cdr=ast_cdr_alloc(); 01212 if (chan->cdr) { 01213 ast_cdr_init(chan->cdr, chan); /* initilize our channel's cdr */ 01214 ast_cdr_start(chan->cdr); 01215 } 01216 } 01217 01218 if (!ast_call(chan, data, timeout)) { 01219 struct timeval started; 01220 int x, len = 0; 01221 char *disconnect_code = NULL, *dialed_code = NULL; 01222 01223 ast_indicate(caller, AST_CONTROL_RINGING); 01224 /* support dialing of the featuremap disconnect code while performing an attended tranfer */ 01225 ast_rwlock_rdlock(&features_lock); 01226 for (x = 0; x < FEATURES_COUNT; x++) { 01227 if (strcasecmp(builtin_features[x].sname, "disconnect")) 01228 continue; 01229 01230 disconnect_code = builtin_features[x].exten; 01231 len = strlen(disconnect_code) + 1; 01232 dialed_code = alloca(len); 01233 memset(dialed_code, 0, len); 01234 break; 01235 } 01236 ast_rwlock_unlock(&features_lock); 01237 x = 0; 01238 started = ast_tvnow(); 01239 to = timeout; 01240 while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) { 01241 struct ast_frame *f = NULL; 01242 01243 monitor_chans[0] = caller; 01244 monitor_chans[1] = chan; 01245 active_channel = ast_waitfor_n(monitor_chans, 2, &to); 01246 01247 /* see if the timeout has been violated */ 01248 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) { 01249 state = AST_CONTROL_UNHOLD; 01250 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n"); 01251 break; /*doh! timeout*/ 01252 } 01253 01254 if (!active_channel) 01255 continue; 01256 01257 if (chan && (chan == active_channel)){ 01258 f = ast_read(chan); 01259 if (f == NULL) { /*doh! where'd he go?*/ 01260 state = AST_CONTROL_HANGUP; 01261 res = 0; 01262 break; 01263 } 01264 01265 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) { 01266 if (f->subclass == AST_CONTROL_RINGING) { 01267 state = f->subclass; 01268 if (option_verbose > 2) 01269 ast_verbose(VERBOSE_PREFIX_3 "%s is ringing\n", chan->name); 01270 ast_indicate(caller, AST_CONTROL_RINGING); 01271 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) { 01272 state = f->subclass; 01273 if (option_verbose > 2) 01274 ast_verbose(VERBOSE_PREFIX_3 "%s is busy\n", chan->name); 01275 ast_indicate(caller, AST_CONTROL_BUSY); 01276 ast_frfree(f); 01277 f = NULL; 01278 break; 01279 } else if (f->subclass == AST_CONTROL_ANSWER) { 01280 /* This is what we are hoping for */ 01281 state = f->subclass; 01282 ast_frfree(f); 01283 f = NULL; 01284 ready=1; 01285 break; 01286 } else if (f->subclass != -1) { 01287 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass); 01288 } 01289 /* else who cares */ 01290 } 01291 01292 } else if (caller && (active_channel == caller)) { 01293 f = ast_read(caller); 01294 if (f == NULL) { /*doh! where'd he go?*/ 01295 if (caller->_softhangup && !chan->_softhangup) { 01296 /* make this a blind transfer */ 01297 ready = 1; 01298 break; 01299 } 01300 state = AST_CONTROL_HANGUP; 01301 res = 0; 01302 break; 01303 } 01304 01305 if (f->frametype == AST_FRAME_DTMF) { 01306 dialed_code[x++] = f->subclass; 01307 dialed_code[x] = '\0'; 01308 if (strlen(dialed_code) == len) { 01309 x = 0; 01310 } else if (x && strncmp(dialed_code, disconnect_code, x)) { 01311 x = 0; 01312 dialed_code[x] = '\0'; 01313 } 01314 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) { 01315 /* Caller Canceled the call */ 01316 state = AST_CONTROL_UNHOLD; 01317 ast_frfree(f); 01318 f = NULL; 01319 break; 01320 } 01321 } 01322 } 01323 if (f) 01324 ast_frfree(f); 01325 } /* end while */ 01326 } else 01327 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data); 01328 } else { 01329 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data); 01330 switch(cause) { 01331 case AST_CAUSE_BUSY: 01332 state = AST_CONTROL_BUSY; 01333 break; 01334 case AST_CAUSE_CONGESTION: 01335 state = AST_CONTROL_CONGESTION; 01336 break; 01337 } 01338 } 01339 01340 ast_indicate(caller, -1); 01341 if (chan && ready) { 01342 if (chan->_state == AST_STATE_UP) 01343 state = AST_CONTROL_ANSWER; 01344 res = 0; 01345 } else if(chan) { 01346 res = -1; 01347 ast_hangup(chan); 01348 chan = NULL; 01349 } else { 01350 res = -1; 01351 } 01352 01353 if (outstate) 01354 *outstate = state; 01355 01356 if (chan && res <= 0) { 01357 if (chan->cdr || (chan->cdr = ast_cdr_alloc())) { 01358 char tmp[256]; 01359 ast_cdr_init(chan->cdr, chan); 01360 snprintf(tmp, 256, "%s/%s", type, (char *)data); 01361 ast_cdr_setapp(chan->cdr,"Dial",tmp); 01362 ast_cdr_update(chan); 01363 ast_cdr_start(chan->cdr); 01364 ast_cdr_end(chan->cdr); 01365 /* If the cause wasn't handled properly */ 01366 if (ast_cdr_disposition(chan->cdr,chan->hangupcause)) 01367 ast_cdr_failed(chan->cdr); 01368 } else { 01369 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n"); 01370 } 01371 } 01372 01373 return chan; 01374 }
static AST_LIST_HEAD_STATIC | ( | feature_list | , | |
ast_call_feature | ||||
) | [static] |
int ast_masq_park_call | ( | struct ast_channel * | rchan, | |
struct ast_channel * | host, | |||
int | timeout, | |||
int * | extout | |||
) |
Park a call via a masqueraded channel.
rchan | the real channel to be parked | |
host | the channel to have the parking read to Masquerade the channel rchan into a new, empty channel which is then parked with ast_park_call | |
timeout | is a timeout in milliseconds | |
extout | is a parameter to an int that will hold the parked location, or NULL if you want |
Definition at line 477 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(), and ss_thread().
00478 { 00479 struct ast_channel *chan; 00480 struct ast_frame *f; 00481 char *orig_chan_name = NULL; 00482 00483 /* Make a new, fake channel that we'll use to masquerade in the real one */ 00484 if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) { 00485 ast_log(LOG_WARNING, "Unable to create parked channel\n"); 00486 return -1; 00487 } 00488 00489 /* Make formats okay */ 00490 chan->readformat = rchan->readformat; 00491 chan->writeformat = rchan->writeformat; 00492 ast_channel_masquerade(chan, rchan); 00493 00494 /* Setup the extensions and such */ 00495 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority); 00496 00497 /* Make the masq execute */ 00498 f = ast_read(chan); 00499 if (f) 00500 ast_frfree(f); 00501 00502 orig_chan_name = ast_strdupa(chan->name); 00503 00504 park_call_full(chan, peer, timeout, extout, orig_chan_name); 00505 00506 return 0; 00507 }
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 | ( | parking_lock | ) |
protects all static variables above
int ast_park_call | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
int | timeout, | |||
int * | extout | |||
) |
Park a call and read back parked location.
Definition at line 472 of file res_features.c.
References park_call_full().
Referenced by builtin_blindtransfer(), builtin_parkcall(), iax_park_thread(), and sip_park_thread().
00473 { 00474 return park_call_full(chan, peer, timeout, extout, NULL); 00475 }
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 159 of file res_features.c.
Referenced by builtin_blindtransfer(), dp_lookup(), handle_request_refer(), mgcp_ss(), socket_process(), and ss_thread().
00160 { 00161 return parking_ext; 00162 }
int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
Definition at line 2324 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().
02325 { 02326 struct ast_channel *cur = NULL; 02327 int res = -1; 02328 02329 while ((cur = ast_channel_walk_locked(cur)) != NULL) { 02330 if (!cur->pbx && 02331 (cur != chan) && 02332 (chan->pickupgroup & cur->callgroup) && 02333 ((cur->_state == AST_STATE_RINGING) || 02334 (cur->_state == AST_STATE_RING))) { 02335 break; 02336 } 02337 ast_channel_unlock(cur); 02338 } 02339 if (cur) { 02340 if (option_debug) 02341 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name); 02342 res = ast_answer(chan); 02343 if (res) 02344 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); 02345 res = ast_queue_control(chan, AST_CONTROL_ANSWER); 02346 if (res) 02347 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); 02348 res = ast_channel_masquerade(cur, chan); 02349 if (res) 02350 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */ 02351 ast_channel_unlock(cur); 02352 } else { 02353 if (option_debug) 02354 ast_log(LOG_DEBUG, "No call pickup possible...\n"); 02355 } 02356 return res; 02357 }
char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 164 of file res_features.c.
Referenced by cb_events(), get_destination(), handle_request_invite(), handle_showfeatures(), mgcp_ss(), and ss_thread().
00165 { 00166 return pickup_ext; 00167 }
void ast_register_feature | ( | struct ast_call_feature * | feature | ) |
register new feature into feature_set
feature | an ast_call_feature object which contains a keysequence and a callback function which is called when this keysequence is pressed during a call. |
Definition at line 945 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.
00946 { 00947 if (!feature) { 00948 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 00949 return; 00950 } 00951 00952 AST_LIST_LOCK(&feature_list); 00953 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry); 00954 AST_LIST_UNLOCK(&feature_list); 00955 00956 if (option_verbose >= 2) 00957 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname); 00958 }
AST_RWLOCK_DEFINE_STATIC | ( | features_lock | ) |
void ast_unregister_feature | ( | struct ast_call_feature * | feature | ) |
unregister feature from feature_set
feature | the ast_call_feature object which was registered before |
Definition at line 961 of file res_features.c.
References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free.
00962 { 00963 if (!feature) 00964 return; 00965 00966 AST_LIST_LOCK(&feature_list); 00967 AST_LIST_REMOVE(&feature_list,feature,feature_entry); 00968 AST_LIST_UNLOCK(&feature_list); 00969 free(feature); 00970 }
static void ast_unregister_features | ( | void | ) | [static] |
Remove all features in the list.
Definition at line 973 of file res_features.c.
References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and free.
00974 { 00975 struct ast_call_feature *feature; 00976 00977 AST_LIST_LOCK(&feature_list); 00978 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry))) 00979 free(feature); 00980 AST_LIST_UNLOCK(&feature_list); 00981 }
static int bridge_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 2602 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(), ast_channel::priority, and xfersound.
Referenced by load_module().
02603 { 02604 struct ast_module_user *u; 02605 struct ast_channel *current_dest_chan, *final_dest_chan; 02606 char *tmp_data = NULL; 02607 struct ast_flags opts = { 0, }; 02608 struct ast_bridge_config bconfig = { { 0, }, }; 02609 02610 AST_DECLARE_APP_ARGS(args, 02611 AST_APP_ARG(dest_chan); 02612 AST_APP_ARG(options); 02613 ); 02614 02615 if (ast_strlen_zero(data)) { 02616 ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n"); 02617 return -1; 02618 } 02619 02620 u = ast_module_user_add(chan); 02621 02622 tmp_data = ast_strdupa(data); 02623 AST_STANDARD_APP_ARGS(args, tmp_data); 02624 if (!ast_strlen_zero(args.options)) 02625 ast_app_parse_options(bridge_exec_options, &opts, NULL, args.options); 02626 02627 /* avoid bridge with ourselves */ 02628 if (!strncmp(chan->name, args.dest_chan, 02629 strlen(chan->name) < strlen(args.dest_chan) ? 02630 strlen(chan->name) : strlen(args.dest_chan))) { 02631 ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name); 02632 manager_event(EVENT_FLAG_CALL, "BridgeExec", 02633 "Response: Failed\r\n" 02634 "Reason: Unable to bridge channel to itself\r\n" 02635 "Channel1: %s\r\n" 02636 "Channel2: %s\r\n", 02637 chan->name, args.dest_chan); 02638 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP"); 02639 ast_module_user_remove(u); 02640 return 0; 02641 } 02642 02643 /* make sure we have a valid end point */ 02644 if (!(current_dest_chan = ast_get_channel_by_name_prefix_locked(args.dest_chan, 02645 strlen(args.dest_chan)))) { 02646 ast_log(LOG_WARNING, "Bridge failed because channel %s does not exists or we " 02647 "cannot get its lock\n", args.dest_chan); 02648 manager_event(EVENT_FLAG_CALL, "BridgeExec", 02649 "Response: Failed\r\n" 02650 "Reason: Cannot grab end point\r\n" 02651 "Channel1: %s\r\n" 02652 "Channel2: %s\r\n", chan->name, args.dest_chan); 02653 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT"); 02654 ast_module_user_remove(u); 02655 return 0; 02656 } 02657 ast_mutex_unlock(¤t_dest_chan->lock); 02658 02659 /* answer the channel if needed */ 02660 if (current_dest_chan->_state != AST_STATE_UP) 02661 ast_answer(current_dest_chan); 02662 02663 /* try to allocate a place holder where current_dest_chan will be placed */ 02664 if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 02665 NULL, NULL, 0, "Bridge/%s", current_dest_chan->name))) { 02666 ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan); 02667 manager_event(EVENT_FLAG_CALL, "BridgeExec", 02668 "Response: Failed\r\n" 02669 "Reason: cannot create placeholder\r\n" 02670 "Channel1: %s\r\n" 02671 "Channel2: %s\r\n", chan->name, args.dest_chan); 02672 } 02673 do_bridge_masquerade(current_dest_chan, final_dest_chan); 02674 02675 /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */ 02676 /* try to make compatible, send error if we fail */ 02677 if (ast_channel_make_compatible(chan, final_dest_chan) < 0) { 02678 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name); 02679 manager_event(EVENT_FLAG_CALL, "BridgeExec", 02680 "Response: Failed\r\n" 02681 "Reason: Could not make channels compatible for bridge\r\n" 02682 "Channel1: %s\r\n" 02683 "Channel2: %s\r\n", chan->name, final_dest_chan->name); 02684 ast_hangup(final_dest_chan); /* may be we should return this channel to the PBX? */ 02685 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE"); 02686 ast_module_user_remove(u); 02687 return 0; 02688 } 02689 02690 /* Report that the bridge will be successfull */ 02691 manager_event(EVENT_FLAG_CALL, "BridgeExec", 02692 "Response: Success\r\n" 02693 "Channel1: %s\r\n" 02694 "Channel2: %s\r\n", chan->name, final_dest_chan->name); 02695 02696 /* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */ 02697 if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) { 02698 if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) { 02699 if (ast_waitstream(final_dest_chan, "") < 0) 02700 ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name); 02701 } 02702 } 02703 02704 /* do the bridge */ 02705 ast_bridge_call(chan, final_dest_chan, &bconfig); 02706 02707 /* the bridge has ended, set BRIDGERESULT to SUCCESS. If the other channel has not been hung up, return it to the PBX */ 02708 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS"); 02709 if (!ast_check_hangup(final_dest_chan)) { 02710 if (option_debug) { 02711 ast_log(LOG_DEBUG, "starting new PBX in %s,%s,%d for chan %s\n", 02712 final_dest_chan->context, final_dest_chan->exten, 02713 final_dest_chan->priority, final_dest_chan->name); 02714 } 02715 02716 if (ast_pbx_start(final_dest_chan) != AST_PBX_SUCCESS) { 02717 ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name); 02718 ast_hangup(final_dest_chan); 02719 } else if (option_debug) 02720 ast_log(LOG_DEBUG, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name); 02721 } else { 02722 if (option_debug) 02723 ast_log(LOG_DEBUG, "hangup chan %s since the other endpoint has hung up\n", final_dest_chan->name); 02724 ast_hangup(final_dest_chan); 02725 } 02726 02727 ast_module_user_remove(u); 02728 02729 return 0; 02730 }
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 785 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, config, 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.
00786 { 00787 struct ast_channel *transferer; 00788 struct ast_channel *transferee; 00789 const char *transferer_real_context; 00790 char xferto[256] = ""; 00791 int res; 00792 int outstate=0; 00793 struct ast_channel *newchan; 00794 struct ast_channel *xferchan; 00795 struct ast_bridge_thread_obj *tobj; 00796 struct ast_bridge_config bconfig; 00797 struct ast_frame *f; 00798 int l; 00799 00800 if (option_debug) 00801 ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense); 00802 set_peers(&transferer, &transferee, peer, chan, sense); 00803 transferer_real_context = real_ctx(transferer, transferee); 00804 /* Start autoservice on chan while we talk to the originator */ 00805 ast_autoservice_start(transferee); 00806 ast_indicate(transferee, AST_CONTROL_HOLD); 00807 00808 /* Transfer */ 00809 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY); 00810 if (res < 0) { 00811 finishup(transferee); 00812 return res; 00813 } 00814 if (res > 0) /* If they've typed a digit already, handle it */ 00815 xferto[0] = (char) res; 00816 00817 /* this is specific of atxfer */ 00818 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 00819 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */ 00820 finishup(transferee); 00821 return res; 00822 } 00823 if (res == 0) { 00824 ast_log(LOG_WARNING, "Did not read data.\n"); 00825 finishup(transferee); 00826 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, "")) 00827 return -1; 00828 return FEATURE_RETURN_SUCCESS; 00829 } 00830 00831 /* valid extension, res == 1 */ 00832 if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) { 00833 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context); 00834 finishup(transferee); 00835 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, "")) 00836 return -1; 00837 return FEATURE_RETURN_SUCCESS; 00838 } 00839 00840 l = strlen(xferto); 00841 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); /* append context */ 00842 newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats), 00843 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, transferer->language); 00844 ast_indicate(transferer, -1); 00845 if (!newchan) { 00846 finishup(transferee); 00847 /* any reason besides user requested cancel and busy triggers the failed sound */ 00848 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY && 00849 ast_stream_and_wait(transferer, xferfailsound, transferer->language, "")) 00850 return -1; 00851 return FEATURE_RETURN_SUCCESS; 00852 } 00853 00854 if (check_compat(transferer, newchan)) { 00855 /* we do mean transferee here, NOT transferer */ 00856 finishup(transferee); 00857 return -1; 00858 } 00859 memset(&bconfig,0,sizeof(struct ast_bridge_config)); 00860 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 00861 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 00862 res = ast_bridge_call(transferer, newchan, &bconfig); 00863 if (newchan->_softhangup || !transferer->_softhangup) { 00864 ast_hangup(newchan); 00865 if (ast_stream_and_wait(transferer, xfersound, transferer->language, "")) 00866 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 00867 finishup(transferee); 00868 transferer->_softhangup = 0; 00869 return FEATURE_RETURN_SUCCESS; 00870 } 00871 00872 if (check_compat(transferee, newchan)) { 00873 finishup(transferee); 00874 return -1; 00875 } 00876 00877 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00878 00879 if ((ast_autoservice_stop(transferee) < 0) 00880 || (ast_waitfordigit(transferee, 100) < 0) 00881 || (ast_waitfordigit(newchan, 100) < 0) 00882 || ast_check_hangup(transferee) 00883 || ast_check_hangup(newchan)) { 00884 ast_hangup(newchan); 00885 return -1; 00886 } 00887 00888 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name); 00889 if (!xferchan) { 00890 ast_hangup(newchan); 00891 return -1; 00892 } 00893 /* Make formats okay */ 00894 xferchan->visible_indication = transferer->visible_indication; 00895 xferchan->readformat = transferee->readformat; 00896 xferchan->writeformat = transferee->writeformat; 00897 ast_channel_masquerade(xferchan, transferee); 00898 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority); 00899 xferchan->_state = AST_STATE_UP; 00900 ast_clear_flag(xferchan, AST_FLAGS_ALL); 00901 xferchan->_softhangup = 0; 00902 00903 if ((f = ast_read(xferchan))) 00904 ast_frfree(f); 00905 00906 newchan->_state = AST_STATE_UP; 00907 ast_clear_flag(newchan, AST_FLAGS_ALL); 00908 newchan->_softhangup = 0; 00909 00910 tobj = ast_calloc(1, sizeof(struct ast_bridge_thread_obj)); 00911 if (!tobj) { 00912 ast_hangup(xferchan); 00913 ast_hangup(newchan); 00914 return -1; 00915 } 00916 tobj->chan = newchan; 00917 tobj->peer = xferchan; 00918 tobj->bconfig = *config; 00919 00920 if (ast_stream_and_wait(newchan, xfersound, newchan->language, "")) 00921 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 00922 ast_bridge_call_thread_launch(tobj); 00923 return -1; /* XXX meaning the channel is bridged ? */ 00924 }
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 571 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, monitor_app, option_verbose, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), S_OR, set_peers(), and VERBOSE_PREFIX_3.
00572 { 00573 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 00574 int x = 0; 00575 size_t len; 00576 struct ast_channel *caller_chan, *callee_chan; 00577 00578 if (!monitor_ok) { 00579 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 00580 return -1; 00581 } 00582 00583 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) { 00584 monitor_ok = 0; 00585 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 00586 return -1; 00587 } 00588 00589 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 00590 00591 if (!ast_strlen_zero(courtesytone)) { 00592 if (ast_autoservice_start(callee_chan)) 00593 return -1; 00594 if (ast_stream_and_wait(caller_chan, courtesytone, caller_chan->language, "")) { 00595 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 00596 ast_autoservice_stop(callee_chan); 00597 return -1; 00598 } 00599 if (ast_autoservice_stop(callee_chan)) 00600 return -1; 00601 } 00602 00603 if (callee_chan->monitor) { 00604 if (option_verbose > 3) 00605 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code); 00606 ast_monitor_stop(callee_chan, 1); 00607 return FEATURE_RETURN_SUCCESS; 00608 } 00609 00610 if (caller_chan && callee_chan) { 00611 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT"); 00612 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR"); 00613 00614 if (!touch_format) 00615 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT"); 00616 00617 if (!touch_monitor) 00618 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR"); 00619 00620 if (touch_monitor) { 00621 len = strlen(touch_monitor) + 50; 00622 args = alloca(len); 00623 touch_filename = alloca(len); 00624 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor); 00625 snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename); 00626 } else { 00627 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name)); 00628 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name)); 00629 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 00630 args = alloca(len); 00631 touch_filename = alloca(len); 00632 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id); 00633 snprintf(args, len, "%s|%s|m", S_OR(touch_format, "wav"), touch_filename); 00634 } 00635 00636 for(x = 0; x < strlen(args); x++) { 00637 if (args[x] == '/') 00638 args[x] = '-'; 00639 } 00640 00641 if (option_verbose > 3) 00642 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args); 00643 00644 pbx_exec(callee_chan, monitor_app, args); 00645 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 00646 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 00647 00648 return FEATURE_RETURN_SUCCESS; 00649 } 00650 00651 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); 00652 return -1; 00653 }
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 682 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(), 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.
00683 { 00684 struct ast_channel *transferer; 00685 struct ast_channel *transferee; 00686 const char *transferer_real_context; 00687 char xferto[256]; 00688 int res; 00689 00690 set_peers(&transferer, &transferee, peer, chan, sense); 00691 transferer_real_context = real_ctx(transferer, transferee); 00692 /* Start autoservice on chan while we talk to the originator */ 00693 ast_autoservice_start(transferee); 00694 ast_indicate(transferee, AST_CONTROL_HOLD); 00695 00696 memset(xferto, 0, sizeof(xferto)); 00697 00698 /* Transfer */ 00699 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY); 00700 if (res < 0) { 00701 finishup(transferee); 00702 return -1; /* error ? */ 00703 } 00704 if (res > 0) /* If they've typed a digit already, handle it */ 00705 xferto[0] = (char) res; 00706 00707 ast_stopstream(transferer); 00708 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 00709 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */ 00710 finishup(transferee); 00711 return res; 00712 } 00713 if (!strcmp(xferto, ast_parking_ext())) { 00714 res = finishup(transferee); 00715 if (res) 00716 res = -1; 00717 else if (!ast_park_call(transferee, transferer, 0, NULL)) { /* success */ 00718 /* We return non-zero, but tell the PBX not to hang the channel when 00719 the thread dies -- We have to be careful now though. We are responsible for 00720 hanging up the channel, else it will never be hung up! */ 00721 00722 return (transferer == peer) ? AST_PBX_KEEPALIVE : AST_PBX_NO_HANGUP_PEER; 00723 } else { 00724 ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name); 00725 } 00726 /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */ 00727 } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) { 00728 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", transferee->name); 00729 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name); 00730 res=finishup(transferee); 00731 if (!transferer->cdr) { 00732 transferer->cdr=ast_cdr_alloc(); 00733 if (transferer) { 00734 ast_cdr_init(transferer->cdr, transferer); /* initilize our channel's cdr */ 00735 ast_cdr_start(transferer->cdr); 00736 } 00737 } 00738 if (transferer->cdr) { 00739 ast_cdr_setdestchan(transferer->cdr, transferee->name); 00740 ast_cdr_setapp(transferer->cdr, "BLINDTRANSFER",""); 00741 } 00742 if (!transferee->pbx) { 00743 /* Doh! Use our handy async_goto functions */ 00744 if (option_verbose > 2) 00745 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n" 00746 ,transferee->name, xferto, transferer_real_context); 00747 if (ast_async_goto(transferee, transferer_real_context, xferto, 1)) 00748 ast_log(LOG_WARNING, "Async goto failed :-(\n"); 00749 res = -1; 00750 } else { 00751 /* Set the channel's new extension, since it exists, using transferer context */ 00752 set_c_e_p(transferee, transferer_real_context, xferto, 0); 00753 } 00754 check_goto_on_transfer(transferer); 00755 return res; 00756 } else { 00757 if (option_verbose > 2) 00758 ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context); 00759 } 00760 if (ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0) { 00761 finishup(transferee); 00762 return -1; 00763 } 00764 ast_stopstream(transferer); 00765 res = finishup(transferee); 00766 if (res) { 00767 if (option_verbose > 1) 00768 ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name); 00769 return res; 00770 } 00771 return FEATURE_RETURN_SUCCESS; 00772 }
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 655 of file res_features.c.
References ast_verbose(), FEATURE_RETURN_HANGUP, option_verbose, and VERBOSE_PREFIX_3.
00656 { 00657 if (option_verbose > 3) 00658 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code); 00659 return FEATURE_RETURN_HANGUP; 00660 }
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 538 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_module_user::chan, ast_channel::exten, FEATURE_SENSE_CHAN, ast_channel::priority, and set_peers().
00539 { 00540 struct ast_channel *parker; 00541 struct ast_channel *parkee; 00542 int res = 0; 00543 struct ast_module_user *u; 00544 00545 u = ast_module_user_add(chan); 00546 00547 set_peers(&parker, &parkee, peer, chan, sense); 00548 /* Setup the exten/priority to be s/1 since we don't know 00549 where this call should return */ 00550 strcpy(chan->exten, "s"); 00551 chan->priority = 1; 00552 if (chan->_state != AST_STATE_UP) 00553 res = ast_answer(chan); 00554 if (!res) 00555 res = ast_safe_sleep(chan, 1000); 00556 if (!res) 00557 res = ast_park_call(parkee, parker, 0, NULL); 00558 00559 ast_module_user_remove(u); 00560 00561 if (!res) { 00562 if (sense == FEATURE_SENSE_CHAN) 00563 res = AST_PBX_NO_HANGUP_PEER; 00564 else 00565 res = AST_PBX_KEEPALIVE; 00566 } 00567 return res; 00568 00569 }
static int check_compat | ( | struct ast_channel * | c, | |
struct ast_channel * | newchan | |||
) | [static] |
Definition at line 774 of file res_features.c.
References ast_channel_make_compatible(), ast_hangup(), ast_log(), and LOG_WARNING.
Referenced by builtin_atxfer().
00775 { 00776 if (ast_channel_make_compatible(c, newchan) < 0) { 00777 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", 00778 c->name, newchan->name); 00779 ast_hangup(newchan); 00780 return -1; 00781 } 00782 return 0; 00783 }
static void check_goto_on_transfer | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 187 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().
00188 { 00189 struct ast_channel *xferchan; 00190 const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR"); 00191 char *x, *goto_on_transfer; 00192 struct ast_frame *f; 00193 00194 if (ast_strlen_zero(val)) 00195 return; 00196 00197 goto_on_transfer = ast_strdupa(val); 00198 00199 if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, chan->name))) 00200 return; 00201 00202 for (x = goto_on_transfer; x && *x; x++) { 00203 if (*x == '^') 00204 *x = '|'; 00205 } 00206 /* Make formats okay */ 00207 xferchan->readformat = chan->readformat; 00208 xferchan->writeformat = chan->writeformat; 00209 ast_channel_masquerade(xferchan, chan); 00210 ast_parseable_goto(xferchan, goto_on_transfer); 00211 xferchan->_state = AST_STATE_UP; 00212 ast_clear_flag(xferchan, AST_FLAGS_ALL); 00213 xferchan->_softhangup = 0; 00214 if ((f = ast_read(xferchan))) { 00215 ast_frfree(f); 00216 f = NULL; 00217 ast_pbx_start(xferchan); 00218 } else { 00219 ast_hangup(xferchan); 00220 } 00221 }
static void do_bridge_masquerade | ( | struct ast_channel * | chan, | |
struct ast_channel * | tmpchan | |||
) | [static] |
Definition at line 2063 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().
02064 { 02065 ast_moh_stop(chan); 02066 ast_mutex_lock(&chan->lock); 02067 ast_setstate(tmpchan, chan->_state); 02068 tmpchan->readformat = chan->readformat; 02069 tmpchan->writeformat = chan->writeformat; 02070 ast_channel_masquerade(tmpchan, chan); 02071 ast_mutex_lock(&tmpchan->lock); 02072 ast_do_masquerade(tmpchan); 02073 /* when returning from bridge, the channel will continue at the next priority */ 02074 ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1); 02075 ast_mutex_unlock(&tmpchan->lock); 02076 ast_mutex_unlock(&chan->lock); 02077 }
static void* do_parking_thread | ( | void * | ignore | ) | [static] |
Take care of parked calls and unpark them if needed.
Definition at line 1672 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::fds, free, LOG_DEBUG, LOG_ERROR, LOG_WARNING, parkeduser::moh_trys, parkeduser::next, notify_metermaids(), parkeduser::notquiteyet, option_debug, option_verbose, parkeduser::parkingexten, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, post_manager_event(), ast_channel::priority, parkeduser::priority, S_OR, set_c_e_p(), parkeduser::start, strdup, and VERBOSE_PREFIX_2.
Referenced by load_module().
01673 { 01674 fd_set rfds, efds; /* results from previous select, to be preserved across loops. */ 01675 FD_ZERO(&rfds); 01676 FD_ZERO(&efds); 01677 01678 for (;;) { 01679 struct parkeduser *pu, *pl, *pt = NULL; 01680 int ms = -1; /* select timeout, uninitialized */ 01681 int max = -1; /* max fd, none there yet */ 01682 fd_set nrfds, nefds; /* args for the next select */ 01683 FD_ZERO(&nrfds); 01684 FD_ZERO(&nefds); 01685 01686 ast_mutex_lock(&parking_lock); 01687 pl = NULL; 01688 pu = parkinglot; 01689 /* navigate the list with prev-cur pointers to support removals */ 01690 while (pu) { 01691 struct ast_channel *chan = pu->chan; /* shorthand */ 01692 int tms; /* timeout for this item */ 01693 int x; /* fd index in channel */ 01694 struct ast_context *con; 01695 01696 if (pu->notquiteyet) { /* Pretend this one isn't here yet */ 01697 pl = pu; 01698 pu = pu->next; 01699 continue; 01700 } 01701 tms = ast_tvdiff_ms(ast_tvnow(), pu->start); 01702 if (tms > pu->parkingtime) { 01703 ast_indicate(chan, AST_CONTROL_UNHOLD); 01704 /* Get chan, exten from derived kludge */ 01705 if (pu->peername[0]) { 01706 char *peername = ast_strdupa(pu->peername); 01707 char *cp = strrchr(peername, '-'); 01708 if (cp) 01709 *cp = 0; 01710 con = ast_context_find(parking_con_dial); 01711 if (!con) { 01712 con = ast_context_create(NULL, parking_con_dial, registrar); 01713 if (!con) 01714 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial); 01715 } 01716 if (con) { 01717 char returnexten[AST_MAX_EXTENSION]; 01718 snprintf(returnexten, sizeof(returnexten), "%s||t", peername); 01719 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar); 01720 } 01721 set_c_e_p(chan, parking_con_dial, peername, 1); 01722 } else { 01723 /* They've been waiting too long, send them back to where they came. Theoretically they 01724 should have their original extensions and such, but we copy to be on the safe side */ 01725 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 01726 } 01727 01728 post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan); 01729 01730 if (option_verbose > 1) 01731 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); 01732 /* Start up the PBX, or hang them up */ 01733 if (ast_pbx_start(chan)) { 01734 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name); 01735 ast_hangup(chan); 01736 } 01737 /* And take them out of the parking lot */ 01738 if (pl) 01739 pl->next = pu->next; 01740 else 01741 parkinglot = pu->next; 01742 pt = pu; 01743 pu = pu->next; 01744 con = ast_context_find(parking_con); 01745 if (con) { 01746 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL)) 01747 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 01748 else 01749 notify_metermaids(pt->parkingexten, parking_con); 01750 } else 01751 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 01752 free(pt); 01753 } else { /* still within parking time, process descriptors */ 01754 for (x = 0; x < AST_MAX_FDS; x++) { 01755 struct ast_frame *f; 01756 01757 if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds))) 01758 continue; /* nothing on this descriptor */ 01759 01760 if (FD_ISSET(chan->fds[x], &efds)) 01761 ast_set_flag(chan, AST_FLAG_EXCEPTION); 01762 else 01763 ast_clear_flag(chan, AST_FLAG_EXCEPTION); 01764 chan->fdno = x; 01765 01766 /* See if they need servicing */ 01767 f = ast_read(chan); 01768 if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP)) { 01769 if (f) 01770 ast_frfree(f); 01771 post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan); 01772 01773 /* There's a problem, hang them up*/ 01774 if (option_verbose > 1) 01775 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name); 01776 ast_hangup(chan); 01777 /* And take them out of the parking lot */ 01778 if (pl) 01779 pl->next = pu->next; 01780 else 01781 parkinglot = pu->next; 01782 pt = pu; 01783 pu = pu->next; 01784 con = ast_context_find(parking_con); 01785 if (con) { 01786 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL)) 01787 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 01788 else 01789 notify_metermaids(pt->parkingexten, parking_con); 01790 } else 01791 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 01792 free(pt); 01793 break; 01794 } else { 01795 /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ 01796 ast_frfree(f); 01797 if (pu->moh_trys < 3 && !chan->generatordata) { 01798 if (option_debug) 01799 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n"); 01800 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 01801 S_OR(parkmohclass, NULL), 01802 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 01803 pu->moh_trys++; 01804 } 01805 goto std; /*! \todo XXX Ick: jumping into an else statement??? XXX */ 01806 } 01807 01808 } /* end for */ 01809 if (x >= AST_MAX_FDS) { 01810 std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */ 01811 if (chan->fds[x] > -1) { 01812 FD_SET(chan->fds[x], &nrfds); 01813 FD_SET(chan->fds[x], &nefds); 01814 if (chan->fds[x] > max) 01815 max = chan->fds[x]; 01816 } 01817 } 01818 /* Keep track of our shortest wait */ 01819 if (tms < ms || ms < 0) 01820 ms = tms; 01821 pl = pu; 01822 pu = pu->next; 01823 } 01824 } 01825 } /* end while */ 01826 ast_mutex_unlock(&parking_lock); 01827 rfds = nrfds; 01828 efds = nefds; 01829 { 01830 struct timeval tv = ast_samp2tv(ms, 1000); 01831 /* Wait for something to happen */ 01832 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL); 01833 } 01834 pthread_testcancel(); 01835 } 01836 return NULL; /* Never reached */ 01837 }
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 997 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().
00998 { 00999 struct ast_app *app; 01000 struct ast_call_feature *feature = data; 01001 struct ast_channel *work, *idle; 01002 int res; 01003 01004 if (!feature) { /* shouldn't ever happen! */ 01005 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n"); 01006 return -1; 01007 } 01008 01009 if (sense == FEATURE_SENSE_CHAN) { 01010 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 01011 return FEATURE_RETURN_KEEPTRYING; 01012 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 01013 work = chan; 01014 idle = peer; 01015 } else { 01016 work = peer; 01017 idle = chan; 01018 } 01019 } else { 01020 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 01021 return FEATURE_RETURN_KEEPTRYING; 01022 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 01023 work = peer; 01024 idle = chan; 01025 } else { 01026 work = chan; 01027 idle = peer; 01028 } 01029 } 01030 01031 if (!(app = pbx_findapp(feature->app))) { 01032 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app); 01033 return -2; 01034 } 01035 01036 ast_autoservice_start(idle); 01037 01038 if (!ast_strlen_zero(feature->moh_class)) 01039 ast_moh_start(idle, feature->moh_class, NULL); 01040 01041 res = pbx_exec(work, app, feature->app_args); 01042 01043 if (!ast_strlen_zero(feature->moh_class)) 01044 ast_moh_stop(idle); 01045 01046 ast_autoservice_stop(idle); 01047 01048 if (res == AST_PBX_KEEPALIVE) 01049 return FEATURE_RETURN_PBX_KEEPALIVE; 01050 else if (res == AST_PBX_NO_HANGUP_PEER) 01051 return FEATURE_RETURN_NO_HANGUP_PEER; 01052 else if (res) 01053 return FEATURE_RETURN_SUCCESSBREAK; 01054 01055 return FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */ 01056 }
static struct ast_call_feature* find_dynamic_feature | ( | const char * | name | ) | [static] |
find a feature by name
Definition at line 984 of file res_features.c.
References AST_LIST_TRAVERSE, and ast_call_feature::sname.
Referenced by ast_feature_interpret(), and set_config_flags().
00985 { 00986 struct ast_call_feature *tmp; 00987 00988 AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) { 00989 if (!strcasecmp(tmp->sname, name)) 00990 break; 00991 } 00992 00993 return tmp; 00994 }
static int finishup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 662 of file res_features.c.
References ast_autoservice_stop(), AST_CONTROL_UNHOLD, and ast_indicate().
Referenced by builtin_atxfer(), and builtin_blindtransfer().
00663 { 00664 ast_indicate(chan, AST_CONTROL_UNHOLD); 00665 00666 return ast_autoservice_stop(chan); 00667 }
static int handle_parkedcalls | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 2178 of file res_features.c.
References ast_cli(), ast_mutex_lock(), ast_mutex_unlock(), parkeduser::chan, parkeduser::context, parkeduser::exten, parkeduser::next, parkeduser::parkingexten, parkinglot, parkeduser::parkingtime, parkeduser::priority, RESULT_SUCCESS, and parkeduser::start.
02179 { 02180 struct parkeduser *cur; 02181 int numparked = 0; 02182 02183 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel" 02184 , "Context", "Extension", "Pri", "Timeout"); 02185 02186 ast_mutex_lock(&parking_lock); 02187 02188 for (cur = parkinglot; cur; cur = cur->next) { 02189 ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n" 02190 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten 02191 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)); 02192 02193 numparked++; 02194 } 02195 ast_mutex_unlock(&parking_lock); 02196 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : ""); 02197 02198 02199 return RESULT_SUCCESS; 02200 }
static int handle_showfeatures | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 2018 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(), builtin_features, ast_call_feature::default_exten, ast_call_feature::exten, exten, FEATURES_COUNT, ast_call_feature::fname, format, parking_con, parking_ext, parking_start, parking_stop, RESULT_SUCCESS, and ast_call_feature::sname.
02019 { 02020 int i; 02021 struct ast_call_feature *feature; 02022 char format[] = "%-25s %-7s %-7s\n"; 02023 02024 ast_cli(fd, format, "Builtin Feature", "Default", "Current"); 02025 ast_cli(fd, format, "---------------", "-------", "-------"); 02026 02027 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */ 02028 02029 ast_rwlock_rdlock(&features_lock); 02030 for (i = 0; i < FEATURES_COUNT; i++) 02031 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten); 02032 ast_rwlock_unlock(&features_lock); 02033 02034 ast_cli(fd, "\n"); 02035 ast_cli(fd, format, "Dynamic Feature", "Default", "Current"); 02036 ast_cli(fd, format, "---------------", "-------", "-------"); 02037 if (AST_LIST_EMPTY(&feature_list)) 02038 ast_cli(fd, "(none)\n"); 02039 else { 02040 AST_LIST_LOCK(&feature_list); 02041 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) 02042 ast_cli(fd, format, feature->sname, "no def", feature->exten); 02043 AST_LIST_UNLOCK(&feature_list); 02044 } 02045 ast_cli(fd, "\nCall parking\n"); 02046 ast_cli(fd, "------------\n"); 02047 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext); 02048 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con); 02049 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop); 02050 ast_cli(fd,"\n"); 02051 02052 return RESULT_SUCCESS; 02053 }
static int load_config | ( | void | ) | [static] |
Definition at line 2374 of file res_features.c.
References adsipark, ast_config_load(), ast_log(), AST_MAX_EXTENSION, AST_MODULE_LOAD_DECLINE, ast_strlen_zero(), ast_variable_browse(), atxfernoanswertimeout, courtesytone, DEFAULT_FEATURE_DIGIT_TIMEOUT, DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER, DEFAULT_TRANSFER_DIGIT_TIMEOUT, featuredigittimeout, LOG_WARNING, parkaddhints, parkfindnext, parking_con, parking_con_dial, parking_ext, parking_start, parking_stop, parkmohclass, pickup_ext, transferdigittimeout, var, xferfailsound, and xfersound.
02375 { 02376 int start = 0, end = 0; 02377 int res; 02378 struct ast_context *con = NULL; 02379 struct ast_config *cfg = NULL; 02380 struct ast_variable *var = NULL; 02381 char old_parking_ext[AST_MAX_EXTENSION]; 02382 char old_parking_con[AST_MAX_EXTENSION] = ""; 02383 02384 if (!ast_strlen_zero(parking_con)) { 02385 strcpy(old_parking_ext, parking_ext); 02386 strcpy(old_parking_con, parking_con); 02387 } 02388 02389 /* Reset to defaults */ 02390 strcpy(parking_con, "parkedcalls"); 02391 strcpy(parking_con_dial, "park-dial"); 02392 strcpy(parking_ext, "700"); 02393 strcpy(pickup_ext, "*8"); 02394 strcpy(parkmohclass, "default"); 02395 courtesytone[0] = '\0'; 02396 strcpy(xfersound, "beep"); 02397 strcpy(xferfailsound, "pbx-invalid"); 02398 parking_start = 701; 02399 parking_stop = 750; 02400 parkfindnext = 0; 02401 adsipark = 0; 02402 parkaddhints = 0; 02403 02404 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 02405 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 02406 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 02407 02408 cfg = ast_config_load("features.conf"); 02409 if (!cfg) { 02410 ast_log(LOG_WARNING,"Could not load features.conf\n"); 02411 return AST_MODULE_LOAD_DECLINE; 02412 } 02413 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { 02414 if (!strcasecmp(var->name, "parkext")) { 02415 ast_copy_string(parking_ext, var->value, sizeof(parking_ext)); 02416 } else if (!strcasecmp(var->name, "context")) { 02417 ast_copy_string(parking_con, var->value, sizeof(parking_con)); 02418 } else if (!strcasecmp(var->name, "parkingtime")) { 02419 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) { 02420 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value); 02421 parkingtime = DEFAULT_PARK_TIME; 02422 } else 02423 parkingtime = parkingtime * 1000; 02424 } else if (!strcasecmp(var->name, "parkpos")) { 02425 if (sscanf(var->value, "%d-%d", &start, &end) != 2) { 02426 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); 02427 } else { 02428 parking_start = start; 02429 parking_stop = end; 02430 } 02431 } else if (!strcasecmp(var->name, "findslot")) { 02432 parkfindnext = (!strcasecmp(var->value, "next")); 02433 } else if (!strcasecmp(var->name, "parkinghints")) { 02434 parkaddhints = ast_true(var->value); 02435 } else if (!strcasecmp(var->name, "adsipark")) { 02436 adsipark = ast_true(var->value); 02437 } else if (!strcasecmp(var->name, "transferdigittimeout")) { 02438 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) { 02439 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value); 02440 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 02441 } else 02442 transferdigittimeout = transferdigittimeout * 1000; 02443 } else if (!strcasecmp(var->name, "featuredigittimeout")) { 02444 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) { 02445 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value); 02446 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 02447 } 02448 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) { 02449 if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) { 02450 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value); 02451 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 02452 } else 02453 atxfernoanswertimeout = atxfernoanswertimeout * 1000; 02454 } else if (!strcasecmp(var->name, "courtesytone")) { 02455 ast_copy_string(courtesytone, var->value, sizeof(courtesytone)); 02456 } else if (!strcasecmp(var->name, "parkedplay")) { 02457 if (!strcasecmp(var->value, "both")) 02458 parkedplay = 2; 02459 else if (!strcasecmp(var->value, "parked")) 02460 parkedplay = 1; 02461 else 02462 parkedplay = 0; 02463 } else if (!strcasecmp(var->name, "xfersound")) { 02464 ast_copy_string(xfersound, var->value, sizeof(xfersound)); 02465 } else if (!strcasecmp(var->name, "xferfailsound")) { 02466 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound)); 02467 } else if (!strcasecmp(var->name, "pickupexten")) { 02468 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext)); 02469 } else if (!strcasecmp(var->name, "parkedmusicclass")) { 02470 ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass)); 02471 } 02472 } 02473 02474 unmap_features(); 02475 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) { 02476 if (remap_feature(var->name, var->value)) 02477 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); 02478 } 02479 02480 /* Map a key combination to an application*/ 02481 ast_unregister_features(); 02482 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) { 02483 char *tmp_val = ast_strdupa(var->value); 02484 char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 02485 struct ast_call_feature *feature; 02486 02487 /* strsep() sets the argument to NULL if match not found, and it 02488 * is safe to use it with a NULL argument, so we don't check 02489 * between calls. 02490 */ 02491 exten = strsep(&tmp_val,","); 02492 activatedby = strsep(&tmp_val,","); 02493 app = strsep(&tmp_val,","); 02494 app_args = strsep(&tmp_val,","); 02495 moh_class = strsep(&tmp_val,","); 02496 02497 activateon = strsep(&activatedby, "/"); 02498 02499 /*! \todo XXX var_name or app_args ? */ 02500 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) { 02501 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n", 02502 app, exten, activateon, var->name); 02503 continue; 02504 } 02505 02506 AST_LIST_LOCK(&feature_list); 02507 if ((feature = find_dynamic_feature(var->name))) { 02508 AST_LIST_UNLOCK(&feature_list); 02509 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name); 02510 continue; 02511 } 02512 AST_LIST_UNLOCK(&feature_list); 02513 02514 if (!(feature = ast_calloc(1, sizeof(*feature)))) 02515 continue; 02516 02517 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN); 02518 ast_copy_string(feature->app, app, FEATURE_APP_LEN); 02519 ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN); 02520 02521 if (app_args) 02522 ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN); 02523 02524 if (moh_class) 02525 ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN); 02526 02527 ast_copy_string(feature->exten, exten, sizeof(feature->exten)); 02528 feature->operation = feature_exec_app; 02529 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF); 02530 02531 /* Allow caller and calle to be specified for backwards compatability */ 02532 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) 02533 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF); 02534 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) 02535 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER); 02536 else { 02537 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s'," 02538 " must be 'self', or 'peer'\n", var->name); 02539 continue; 02540 } 02541 02542 if (ast_strlen_zero(activatedby)) 02543 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 02544 else if (!strcasecmp(activatedby, "caller")) 02545 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER); 02546 else if (!strcasecmp(activatedby, "callee")) 02547 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE); 02548 else if (!strcasecmp(activatedby, "both")) 02549 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 02550 else { 02551 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s'," 02552 " must be 'caller', or 'callee', or 'both'\n", var->name); 02553 continue; 02554 } 02555 02556 ast_register_feature(feature); 02557 02558 if (option_verbose >= 1) 02559 ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten); 02560 } 02561 ast_config_destroy(cfg); 02562 02563 /* Remove the old parking extension */ 02564 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) { 02565 if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar)) 02566 notify_metermaids(old_parking_ext, old_parking_con); 02567 if (option_debug) 02568 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con); 02569 } 02570 02571 if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) { 02572 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); 02573 return -1; 02574 } 02575 res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar); 02576 if (parkaddhints) 02577 park_add_hints(parking_con, parking_start, parking_stop); 02578 if (!res) 02579 notify_metermaids(ast_parking_ext(), parking_con); 02580 return res; 02581 02582 }
static int load_module | ( | void | ) | [static] |
Definition at line 2737 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(), bridge_exec(), cli_features, descrip, descrip2, do_parking_thread(), EVENT_FLAG_CALL, EVENT_FLAG_COMMAND, load_config(), manager_park(), manager_parking_status(), mandescr_bridge, mandescr_park, metermaidstate(), park_call_exec(), park_exec(), parkcall, parkedcall, parking_con, parking_ext, parking_thread, synopsis, and synopsis2.
02738 { 02739 int res; 02740 02741 ast_register_application(app_bridge, bridge_exec, bridge_synopsis, bridge_descrip); 02742 02743 memset(parking_ext, 0, sizeof(parking_ext)); 02744 memset(parking_con, 0, sizeof(parking_con)); 02745 02746 if ((res = load_config())) 02747 return res; 02748 ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); 02749 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL); 02750 res = ast_register_application(parkedcall, park_exec, synopsis, descrip); 02751 if (!res) 02752 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2); 02753 if (!res) { 02754 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls"); 02755 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park, 02756 "Park a channel", mandescr_park); 02757 ast_manager_register2("Bridge", EVENT_FLAG_COMMAND, action_bridge, "Bridge two channels already in the PBX", mandescr_bridge); 02758 } 02759 02760 res |= ast_devstate_prov_add("Park", metermaidstate); 02761 02762 return res; 02763 }
static int manager_park | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 2269 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(), astman_send_error(), s, and timeout.
Referenced by load_module().
02270 { 02271 const char *channel = astman_get_header(m, "Channel"); 02272 const char *channel2 = astman_get_header(m, "Channel2"); 02273 const char *timeout = astman_get_header(m, "Timeout"); 02274 char buf[BUFSIZ]; 02275 int to = 0; 02276 int res = 0; 02277 int parkExt = 0; 02278 struct ast_channel *ch1, *ch2; 02279 02280 if (ast_strlen_zero(channel)) { 02281 astman_send_error(s, m, "Channel not specified"); 02282 return 0; 02283 } 02284 02285 if (ast_strlen_zero(channel2)) { 02286 astman_send_error(s, m, "Channel2 not specified"); 02287 return 0; 02288 } 02289 02290 ch1 = ast_get_channel_by_name_locked(channel); 02291 if (!ch1) { 02292 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel); 02293 astman_send_error(s, m, buf); 02294 return 0; 02295 } 02296 02297 ch2 = ast_get_channel_by_name_locked(channel2); 02298 if (!ch2) { 02299 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2); 02300 astman_send_error(s, m, buf); 02301 ast_channel_unlock(ch1); 02302 return 0; 02303 } 02304 02305 if (!ast_strlen_zero(timeout)) { 02306 sscanf(timeout, "%d", &to); 02307 } 02308 02309 res = ast_masq_park_call(ch1, ch2, to, &parkExt); 02310 if (!res) { 02311 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT); 02312 astman_send_ack(s, m, "Park successful"); 02313 } else { 02314 astman_send_error(s, m, "Park failure"); 02315 } 02316 02317 ast_channel_unlock(ch1); 02318 ast_channel_unlock(ch2); 02319 02320 return 0; 02321 }
static int manager_parking_status | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Dump lot status.
Definition at line 2222 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, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, RESULT_SUCCESS, s, S_OR, and parkeduser::start.
Referenced by load_module().
02223 { 02224 struct parkeduser *cur; 02225 const char *id = astman_get_header(m, "ActionID"); 02226 char idText[256] = ""; 02227 02228 if (!ast_strlen_zero(id)) 02229 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 02230 02231 astman_send_ack(s, m, "Parked calls will follow"); 02232 02233 ast_mutex_lock(&parking_lock); 02234 02235 for (cur = parkinglot; cur; cur = cur->next) { 02236 astman_append(s, "Event: ParkedCall\r\n" 02237 "Exten: %d\r\n" 02238 "Channel: %s\r\n" 02239 "From: %s\r\n" 02240 "Timeout: %ld\r\n" 02241 "CallerID: %s\r\n" 02242 "CallerIDName: %s\r\n" 02243 "%s" 02244 "\r\n", 02245 cur->parkingnum, cur->chan->name, cur->peername, 02246 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL), 02247 S_OR(cur->chan->cid.cid_num, ""), /* XXX in other places it is <unknown> */ 02248 S_OR(cur->chan->cid.cid_name, ""), 02249 idText); 02250 } 02251 02252 astman_append(s, 02253 "Event: ParkedCallsComplete\r\n" 02254 "%s" 02255 "\r\n",idText); 02256 02257 ast_mutex_unlock(&parking_lock); 02258 02259 return RESULT_SUCCESS; 02260 }
static int metermaidstate | ( | const char * | data | ) | [static] |
metermaids callback from devicestate.c
Definition at line 313 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().
00314 { 00315 int res = AST_DEVICE_INVALID; 00316 char *context = ast_strdupa(data); 00317 char *exten; 00318 00319 exten = strsep(&context, "@"); 00320 if (!context) 00321 return res; 00322 00323 if (option_debug > 3) 00324 ast_log(LOG_DEBUG, "Checking state of exten %s in context %s\n", exten, context); 00325 00326 res = ast_exists_extension(NULL, context, exten, 1, NULL); 00327 00328 if (!res) 00329 return AST_DEVICE_NOT_INUSE; 00330 else 00331 return AST_DEVICE_INUSE; 00332 }
static void notify_metermaids | ( | char * | exten, | |
char * | context | |||
) | [static] |
Notify metermaids that we've changed an extension.
Definition at line 302 of file res_features.c.
References ast_device_state_changed(), ast_log(), LOG_DEBUG, and option_debug.
Referenced by do_parking_thread(), park_call_full(), and park_exec().
00303 { 00304 if (option_debug > 3) 00305 ast_log(LOG_DEBUG, "Notification of state change to metermaids %s@%s\n", exten, context); 00306 00307 /* Send notification to devicestate subsystem */ 00308 ast_device_state_changed("park:%s@%s", exten, context); 00309 return; 00310 }
static void park_add_hints | ( | char * | context, | |
int | start, | |||
int | stop | |||
) | [static] |
Add parking hints for all defined parking lots.
Definition at line 2360 of file res_features.c.
References ast_add_extension(), AST_MAX_EXTENSION, exten, PRIORITY_HINT, and registrar.
02361 { 02362 int numext; 02363 char device[AST_MAX_EXTENSION]; 02364 char exten[10]; 02365 02366 for (numext = start; numext <= stop; numext++) { 02367 snprintf(exten, sizeof(exten), "%d", numext); 02368 snprintf(device, sizeof(device), "park:%s@%s", exten, context); 02369 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar); 02370 } 02371 }
static int park_call_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Park a call.
Definition at line 1840 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_module_user::chan, ast_channel::exten, orig_exten(), park_call_full(), and ast_channel::priority.
Referenced by load_module().
01841 { 01842 /* Cache the original channel name in case we get masqueraded in the middle 01843 * of a park--it is still theoretically possible for a transfer to happen before 01844 * we get here, but it is _really_ unlikely */ 01845 char *orig_chan_name = ast_strdupa(chan->name); 01846 char orig_exten[AST_MAX_EXTENSION]; 01847 int orig_priority = chan->priority; 01848 01849 /* Data is unused at the moment but could contain a parking 01850 lot context eventually */ 01851 int res = 0; 01852 struct ast_module_user *u; 01853 01854 u = ast_module_user_add(chan); 01855 01856 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten)); 01857 01858 /* Setup the exten/priority to be s/1 since we don't know 01859 where this call should return */ 01860 strcpy(chan->exten, "s"); 01861 chan->priority = 1; 01862 /* Answer if call is not up */ 01863 if (chan->_state != AST_STATE_UP) 01864 res = ast_answer(chan); 01865 /* Sleep to allow VoIP streams to settle down */ 01866 if (!res) 01867 res = ast_safe_sleep(chan, 1000); 01868 /* Park the call */ 01869 if (!res) { 01870 res = park_call_full(chan, chan, 0, NULL, orig_chan_name); 01871 /* Continue on in the dialplan */ 01872 if (res == 1) { 01873 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten)); 01874 chan->priority = orig_priority; 01875 res = 0; 01876 } else if (!res) 01877 res = AST_PBX_KEEPALIVE; 01878 } 01879 01880 ast_module_user_remove(u); 01881 01882 return res; 01883 }
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 334 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(), ast_channel::context, ast_channel::data, EVENT_FLAG_CALL, ast_channel::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, parkinglot, parkeduser::parkingnum, pbx_builtin_getvar_helper(), ast_channel::priority, S_OR, strdup, and VERBOSE_PREFIX_2.
Referenced by ast_masq_park_call(), ast_park_call(), and park_call_exec().
00335 { 00336 struct parkeduser *pu, *cur; 00337 int i, x = -1, parking_range; 00338 struct ast_context *con; 00339 const char *parkingexten; 00340 00341 /* Allocate memory for parking data */ 00342 if (!(pu = ast_calloc(1, sizeof(*pu)))) 00343 return -1; 00344 00345 /* Lock parking lot */ 00346 ast_mutex_lock(&parking_lock); 00347 /* Check for channel variable PARKINGEXTEN */ 00348 parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN"); 00349 if (!ast_strlen_zero(parkingexten)) { 00350 if (ast_exists_extension(NULL, parking_con, parkingexten, 1, NULL)) { 00351 ast_mutex_unlock(&parking_lock); 00352 free(pu); 00353 ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con); 00354 return 1; /* Continue execution if possible */ 00355 } 00356 ast_copy_string(pu->parkingexten, parkingexten, sizeof(pu->parkingexten)); 00357 x = atoi(parkingexten); 00358 } else { 00359 /* Select parking space within range */ 00360 parking_range = parking_stop - parking_start+1; 00361 for (i = 0; i < parking_range; i++) { 00362 x = (i + parking_offset) % parking_range + parking_start; 00363 cur = parkinglot; 00364 while(cur) { 00365 if (cur->parkingnum == x) 00366 break; 00367 cur = cur->next; 00368 } 00369 if (!cur) 00370 break; 00371 } 00372 00373 if (!(i < parking_range)) { 00374 ast_log(LOG_WARNING, "No more parking spaces\n"); 00375 free(pu); 00376 ast_mutex_unlock(&parking_lock); 00377 return -1; 00378 } 00379 /* Set pointer for next parking */ 00380 if (parkfindnext) 00381 parking_offset = x - parking_start + 1; 00382 } 00383 00384 chan->appl = "Parked Call"; 00385 chan->data = NULL; 00386 00387 pu->chan = chan; 00388 00389 /* Put the parked channel on hold if we have two different channels */ 00390 if (chan != peer) { 00391 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 00392 S_OR(parkmohclass, NULL), 00393 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 00394 } 00395 00396 pu->start = ast_tvnow(); 00397 pu->parkingnum = x; 00398 pu->parkingtime = (timeout > 0) ? timeout : parkingtime; 00399 if (extout) 00400 *extout = x; 00401 00402 if (peer) 00403 ast_copy_string(pu->peername, peer->name, sizeof(pu->peername)); 00404 00405 /* Remember what had been dialed, so that if the parking 00406 expires, we try to come back to the same place */ 00407 ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context)); 00408 ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten)); 00409 pu->priority = chan->macropriority ? chan->macropriority : chan->priority; 00410 pu->next = parkinglot; 00411 parkinglot = pu; 00412 00413 /* If parking a channel directly, don't quiet yet get parking running on it */ 00414 if (peer == chan) 00415 pu->notquiteyet = 1; 00416 ast_mutex_unlock(&parking_lock); 00417 /* Wake up the (presumably select()ing) thread */ 00418 pthread_kill(parking_thread, SIGURG); 00419 if (option_verbose > 1) 00420 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)); 00421 00422 if (pu->parkingnum != -1) 00423 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x); 00424 manager_event(EVENT_FLAG_CALL, "ParkedCall", 00425 "Exten: %s\r\n" 00426 "Channel: %s\r\n" 00427 "From: %s\r\n" 00428 "Timeout: %ld\r\n" 00429 "CallerID: %s\r\n" 00430 "CallerIDName: %s\r\n", 00431 pu->parkingexten, pu->chan->name, peer ? peer->name : "", 00432 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL), 00433 S_OR(pu->chan->cid.cid_num, "<unknown>"), 00434 S_OR(pu->chan->cid.cid_name, "<unknown>") 00435 ); 00436 00437 if (peer && adsipark && ast_adsi_available(peer)) { 00438 adsi_announce_park(peer, pu->parkingexten); /* Only supports parking numbers */ 00439 ast_adsi_unload_session(peer); 00440 } 00441 00442 con = ast_context_find(parking_con); 00443 if (!con) 00444 con = ast_context_create(NULL, parking_con, registrar); 00445 if (!con) /* Still no context? Bad */ 00446 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); 00447 /* Tell the peer channel the number of the parking space */ 00448 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 */ 00449 /* Make sure we don't start saying digits to the channel being parked */ 00450 ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM); 00451 ast_say_digits(peer, pu->parkingnum, "", peer->language); 00452 ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM); 00453 } 00454 if (con) { 00455 if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), ast_free, registrar)) 00456 notify_metermaids(pu->parkingexten, parking_con); 00457 } 00458 if (pu->notquiteyet) { 00459 /* Wake up parking thread if we're really done */ 00460 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 00461 S_OR(parkmohclass, NULL), 00462 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 00463 pu->notquiteyet = 0; 00464 pthread_kill(parking_thread, SIGURG); 00465 } 00466 return 0; 00467 }
static int park_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Pickup parked call.
Definition at line 1886 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(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, config, courtesytone, error(), EVENT_FLAG_CALL, free, LOG_WARNING, manager_event(), parkeduser::next, notify_metermaids(), option_verbose, parkedplay, parking_con, parkeduser::parkingexten, parkinglot, parkeduser::parkingnum, pbx_builtin_setvar_helper(), S_OR, and VERBOSE_PREFIX_3.
Referenced by load_module().
01887 { 01888 int res = 0; 01889 struct ast_module_user *u; 01890 struct ast_channel *peer=NULL; 01891 struct parkeduser *pu, *pl=NULL; 01892 struct ast_context *con; 01893 01894 int park; 01895 struct ast_bridge_config config; 01896 01897 if (!data) { 01898 ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n"); 01899 return -1; 01900 } 01901 01902 u = ast_module_user_add(chan); 01903 01904 park = atoi((char *)data); 01905 ast_mutex_lock(&parking_lock); 01906 pu = parkinglot; 01907 while(pu) { 01908 if (pu->parkingnum == park) { 01909 if (pl) 01910 pl->next = pu->next; 01911 else 01912 parkinglot = pu->next; 01913 break; 01914 } 01915 pl = pu; 01916 pu = pu->next; 01917 } 01918 ast_mutex_unlock(&parking_lock); 01919 if (pu) { 01920 peer = pu->chan; 01921 con = ast_context_find(parking_con); 01922 if (con) { 01923 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL)) 01924 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 01925 else 01926 notify_metermaids(pu->parkingexten, parking_con); 01927 } else 01928 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 01929 01930 manager_event(EVENT_FLAG_CALL, "UnParkedCall", 01931 "Exten: %s\r\n" 01932 "Channel: %s\r\n" 01933 "From: %s\r\n" 01934 "CallerID: %s\r\n" 01935 "CallerIDName: %s\r\n", 01936 pu->parkingexten, pu->chan->name, chan->name, 01937 S_OR(pu->chan->cid.cid_num, "<unknown>"), 01938 S_OR(pu->chan->cid.cid_name, "<unknown>") 01939 ); 01940 01941 free(pu); 01942 } 01943 /* JK02: it helps to answer the channel if not already up */ 01944 if (chan->_state != AST_STATE_UP) 01945 ast_answer(chan); 01946 01947 if (peer) { 01948 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */ 01949 01950 if (!ast_strlen_zero(courtesytone)) { 01951 int error = 0; 01952 ast_indicate(peer, AST_CONTROL_UNHOLD); 01953 if (parkedplay == 0) { 01954 error = ast_stream_and_wait(chan, courtesytone, chan->language, ""); 01955 } else if (parkedplay == 1) { 01956 error = ast_stream_and_wait(peer, courtesytone, chan->language, ""); 01957 } else if (parkedplay == 2) { 01958 if (!ast_streamfile(chan, courtesytone, chan->language) && 01959 !ast_streamfile(peer, courtesytone, chan->language)) { 01960 /*! \todo XXX we would like to wait on both! */ 01961 res = ast_waitstream(chan, ""); 01962 if (res >= 0) 01963 res = ast_waitstream(peer, ""); 01964 if (res < 0) 01965 error = 1; 01966 } 01967 } 01968 if (error) { 01969 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 01970 ast_hangup(peer); 01971 ast_module_user_remove(u); 01972 return -1; 01973 } 01974 } else 01975 ast_indicate(peer, AST_CONTROL_UNHOLD); 01976 01977 res = ast_channel_make_compatible(chan, peer); 01978 if (res < 0) { 01979 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); 01980 ast_hangup(peer); 01981 ast_module_user_remove(u); 01982 return -1; 01983 } 01984 /* This runs sorta backwards, since we give the incoming channel control, as if it 01985 were the person called. */ 01986 if (option_verbose > 2) 01987 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park); 01988 01989 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 01990 ast_cdr_setdestchan(chan->cdr, peer->name); 01991 memset(&config, 0, sizeof(struct ast_bridge_config)); 01992 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 01993 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 01994 res = ast_bridge_call(chan, peer, &config); 01995 01996 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 01997 ast_cdr_setdestchan(chan->cdr, peer->name); 01998 01999 /* Simulate the PBX hanging up */ 02000 if (res != AST_PBX_NO_HANGUP_PEER) 02001 ast_hangup(peer); 02002 ast_module_user_remove(u); 02003 return res; 02004 } else { 02005 /*! \todo XXX Play a message XXX */ 02006 if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, "")) 02007 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name); 02008 if (option_verbose > 2) 02009 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park); 02010 res = -1; 02011 } 02012 02013 ast_module_user_remove(u); 02014 02015 return res; 02016 }
static void post_manager_event | ( | const char * | s, | |
char * | parkingexten, | |||
struct ast_channel * | chan | |||
) | [static] |
Definition at line 1657 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().
01658 { 01659 manager_event(EVENT_FLAG_CALL, s, 01660 "Exten: %s\r\n" 01661 "Channel: %s\r\n" 01662 "CallerID: %s\r\n" 01663 "CallerIDName: %s\r\n\r\n", 01664 parkingexten, 01665 chan->name, 01666 S_OR(chan->cid.cid_num, "<unknown>"), 01667 S_OR(chan->cid.cid_name, "<unknown>") 01668 ); 01669 }
static const char* real_ctx | ( | struct ast_channel * | transferer, | |
struct ast_channel * | transferee | |||
) | [static] |
Find the context for the transfer.
Definition at line 670 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().
00671 { 00672 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"); 00673 if (ast_strlen_zero(s)) 00674 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT"); 00675 if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */ 00676 s = transferer->macrocontext; 00677 if (ast_strlen_zero(s)) 00678 s = transferer->context; 00679 return s; 00680 }
static int reload | ( | void | ) | [static] |
Definition at line 2732 of file res_features.c.
References load_config().
02733 { 02734 return load_config(); 02735 }
static int remap_feature | ( | const char * | name, | |
const char * | value | |||
) | [static] |
Definition at line 1068 of file res_features.c.
References ast_rwlock_unlock(), ast_rwlock_wrlock(), builtin_features, exten, and FEATURES_COUNT.
01069 { 01070 int x, res = -1; 01071 01072 ast_rwlock_wrlock(&features_lock); 01073 for (x = 0; x < FEATURES_COUNT; x++) { 01074 if (strcasecmp(builtin_features[x].sname, name)) 01075 continue; 01076 01077 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten)); 01078 res = 0; 01079 break; 01080 } 01081 ast_rwlock_unlock(&features_lock); 01082 01083 return res; 01084 }
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 180 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().
00181 { 00182 ast_copy_string(chan->context, context, sizeof(chan->context)); 00183 ast_copy_string(chan->exten, ext, sizeof(chan->exten)); 00184 chan->priority = pri; 00185 }
static void set_config_flags | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config | |||
) | [static] |
Definition at line 1152 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, builtin_features, config, ast_call_feature::feature_mask, FEATURES_COUNT, find_dynamic_feature(), pbx_builtin_getvar_helper(), and strsep().
Referenced by ast_bridge_call().
01153 { 01154 int x; 01155 01156 ast_clear_flag(config, AST_FLAGS_ALL); 01157 01158 ast_rwlock_rdlock(&features_lock); 01159 for (x = 0; x < FEATURES_COUNT; x++) { 01160 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) 01161 continue; 01162 01163 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask)) 01164 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 01165 01166 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask)) 01167 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 01168 } 01169 ast_rwlock_unlock(&features_lock); 01170 01171 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) { 01172 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"); 01173 01174 if (dynamic_features) { 01175 char *tmp = ast_strdupa(dynamic_features); 01176 char *tok; 01177 struct ast_call_feature *feature; 01178 01179 /* while we have a feature */ 01180 while ((tok = strsep(&tmp, "#"))) { 01181 AST_LIST_LOCK(&feature_list); 01182 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) { 01183 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 01184 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 01185 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 01186 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 01187 } 01188 AST_LIST_UNLOCK(&feature_list); 01189 } 01190 } 01191 } 01192 }
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 525 of file res_features.c.
References FEATURE_SENSE_PEER.
Referenced by builtin_atxfer(), builtin_automonitor(), builtin_blindtransfer(), and builtin_parkcall().
00527 { 00528 if (sense == FEATURE_SENSE_PEER) { 00529 *caller = peer; 00530 *callee = chan; 00531 } else { 00532 *callee = peer; 00533 *caller = chan; 00534 } 00535 }
static int unload_module | ( | void | ) | [static] |
Definition at line 2766 of file res_features.c.
References ast_cli_unregister_multiple(), ast_devstate_prov_del(), ast_manager_unregister(), ast_module_user_hangup_all, ast_unregister_application(), cli_features, parkcall, and parkedcall.
02767 { 02768 ast_module_user_hangup_all(); 02769 02770 ast_manager_unregister("ParkedCalls"); 02771 ast_manager_unregister("Bridge"); 02772 ast_manager_unregister("Park"); 02773 ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); 02774 ast_unregister_application(parkcall); 02775 ast_unregister_application(app_bridge); 02776 ast_devstate_prov_del("Park"); 02777 return ast_unregister_application(parkedcall); 02778 }
static void unmap_features | ( | void | ) | [static] |
Definition at line 1058 of file res_features.c.
References ast_rwlock_unlock(), ast_rwlock_wrlock(), builtin_features, exten, and FEATURES_COUNT.
01059 { 01060 int x; 01061 01062 ast_rwlock_wrlock(&features_lock); 01063 for (x = 0; x < FEATURES_COUNT; x++) 01064 strcpy(builtin_features[x].exten, builtin_features[x].default_exten); 01065 ast_rwlock_unlock(&features_lock); 01066 }
int adsipark [static] |
char* app_bridge = "Bridge" [static] |
Definition at line 2584 of file res_features.c.
int atxfernoanswertimeout [static] |
char* bridge_descrip [static] |
Definition at line 2586 of file res_features.c.
char* bridge_synopsis = "Bridge two channels" [static] |
Definition at line 2585 of file res_features.c.
struct ast_call_feature builtin_features[] [static] |
Definition at line 932 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().
struct ast_cli_entry cli_features[] [static] |
Definition at line 2211 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 2206 of file res_features.c.
char courtesytone[256] [static] |
Courtesy tone
Definition at line 94 of file res_features.c.
Referenced by load_config(), and park_exec().
char* descrip [static] |
Initial value:
"ParkedCall(exten):" "Used to connect to a parked call. This application is always\n" "registered internally and does not need to be explicitly added\n" "into the dialplan, although you should include the 'parkedcalls'\n" "context.\n"
Definition at line 114 of file res_features.c.
char* descrip2 [static] |
Definition at line 124 of file res_features.c.
int featuredigittimeout [static] |
Definition at line 105 of file res_features.c.
char mandescr_bridge[] [static] |
char mandescr_park[] [static] |
struct ast_app* monitor_app = NULL [static] |
Definition at line 135 of file res_features.c.
Referenced by ast_bridge_call(), and builtin_automonitor().
int monitor_ok = 1 [static] |
Definition at line 136 of file res_features.c.
int parkaddhints = 0 [static] |
Add parking hints automatically
Definition at line 84 of file res_features.c.
Referenced by load_config().
char* parkcall = "Park" [static] |
char* parkedcall = "ParkedCall" [static] |
int parkedplay = 0 [static] |
Who to play the courtesy tone to
Definition at line 95 of file res_features.c.
Referenced by park_exec().
int parkfindnext [static] |
char parking_con[AST_MAX_EXTENSION] [static] |
Context for which parking is made accessible
Definition at line 86 of file res_features.c.
Referenced by handle_showfeatures(), load_config(), load_module(), and park_exec().
char parking_con_dial[AST_MAX_EXTENSION] [static] |
Context for dialback for parking (KLUDGE)
Definition at line 87 of file res_features.c.
Referenced by load_config().
char parking_ext[AST_MAX_EXTENSION] [static] |
Extension you type to park the call
Definition at line 88 of file res_features.c.
Referenced by handle_showfeatures(), load_config(), and load_module().
int parking_offset [static] |
Definition at line 99 of file res_features.c.
int parking_start [static] |
First available extension for parking
Definition at line 91 of file res_features.c.
Referenced by handle_showfeatures(), and load_config().
int parking_stop [static] |
Last available extension for parking
Definition at line 92 of file res_features.c.
Referenced by handle_showfeatures(), and load_config().
pthread_t parking_thread [static] |
struct parkeduser* parkinglot [static] |
Definition at line 153 of file res_features.c.
Referenced by do_parking_thread(), handle_parkedcalls(), manager_parking_status(), park_call_full(), and park_exec().
int parkingtime = DEFAULT_PARK_TIME [static] |
No more than 45 seconds parked before you do something with them
Definition at line 85 of file res_features.c.
char parkmohclass[MAX_MUSICCLASS] [static] |
Music class used for parking
Definition at line 90 of file res_features.c.
Referenced by load_config().
char pickup_ext[AST_MAX_EXTENSION] [static] |
char* registrar = "res_features" [static] |
Registrar for operations
Definition at line 109 of file res_features.c.
char showfeatures_help[] [static] |
Initial value:
"Usage: feature list\n" " Lists currently configured features.\n"
Definition at line 2174 of file res_features.c.
char showparked_help[] [static] |
Initial value:
"Usage: show parkedcalls\n" " Lists currently parked calls.\n"
Definition at line 2202 of file res_features.c.
char* synopsis = "Answer a parked call" [static] |
Definition at line 112 of file res_features.c.
char* synopsis2 = "Park yourself" [static] |
Definition at line 122 of file res_features.c.
int transferdigittimeout [static] |
char xferfailsound[256] [static] |
Call transfer failure sound
Definition at line 97 of file res_features.c.
Referenced by load_config().
char xfersound[256] [static] |
Call transfer sound
Definition at line 96 of file res_features.c.
Referenced by action_bridge(), bridge_exec(), and load_config().