#include "asterisk.h"
#include <pthread.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/options.h"
#include "asterisk/causes.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/app.h"
#include "asterisk/say.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/config.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/utils.h"
#include "asterisk/adsi.h"
#include "asterisk/devicestate.h"
#include "asterisk/monitor.h"
#include "asterisk/global_datastores.h"
Go to the source code of this file.
Data Structures | |
struct | ast_bridge_thread_obj |
struct | feature_list |
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_PASSDIGITS 21 |
#define | FEATURE_RETURN_STOREDIGITS 22 |
#define | FEATURE_RETURN_SUCCESS 23 |
#define | FEATURE_RETURN_SUCCESSBREAK 0 |
#define | FEATURE_SENSE_CHAN (1 << 0) |
#define | FEATURE_SENSE_PEER (1 << 1) |
#define | FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0])) |
Enumerations | |
enum | { AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0), AST_FEATURE_FLAG_ONPEER = (1 << 1), AST_FEATURE_FLAG_ONSELF = (1 << 2), AST_FEATURE_FLAG_BYCALLEE = (1 << 3), AST_FEATURE_FLAG_BYCALLER = (1 << 4), AST_FEATURE_FLAG_BYBOTH = (3 << 3) } |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static int | adsi_announce_park (struct ast_channel *chan, char *parkingexten) |
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) |
int | ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout) |
Park a call via a masqueraded channel. | |
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 | |
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 | builtin_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data) |
Attended transfer (). | |
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 | cmd_atxfer (struct ast_channel *a, struct ast_channel *b, struct ast_bridge_config *conf, struct ast_channel *who, char *xferto) |
static int | do_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, int sense, const char *toExt, const char *toCont) |
Attended transfer implementation. | |
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 | masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, int play_announcement, const char *orig_chan_name) |
static int | masq_park_call_announce (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, const char *orig_chan_name) |
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, const char *orig_chan_name) |
static int | park_exec (struct ast_channel *chan, void *data) |
Pickup parked call. | |
static struct ast_cdr * | pick_unlocked_cdr (struct ast_cdr *cdr) |
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 struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_BUILDSUM, .description = "Call Features Resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "f450f61f60e761b3aa089ebed76ca8a5" , .load = load_module, .unload = unload_module, .reload = reload, } |
static int | adsipark |
static const struct ast_module_info * | ast_module_info = &__mod_info |
static int | atxfernoanswertimeout |
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 ast_rwlock_t | features_lock = PTHREAD_RWLOCK_INITIALIZER |
static char | mandescr_park [] |
static struct ast_app * | monitor_app = NULL |
static int | monitor_ok = 1 |
static int | parkaddhints = 0 |
static char * | parkcall = PARK_APP_NAME |
static char * | parkedcall = "ParkedCall" |
static int | parkedcalltransfers |
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 ast_mutex_t | parking_lock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) |
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 72 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 67 of file res_features.c.
#define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 |
#define FEATURE_RETURN_HANGUP -1 |
#define FEATURE_RETURN_KEEPTRYING 24 |
Definition at line 544 of file res_features.c.
Referenced by ast_feature_interpret(), and feature_exec_app().
#define FEATURE_RETURN_PASSDIGITS 21 |
Definition at line 541 of file res_features.c.
Referenced by ast_bridge_call(), and ast_feature_interpret().
#define FEATURE_RETURN_STOREDIGITS 22 |
#define FEATURE_RETURN_SUCCESS 23 |
Definition at line 543 of file res_features.c.
Referenced by ast_bridge_call(), builtin_automonitor(), builtin_blindtransfer(), do_atxfer(), and feature_exec_app().
#define FEATURE_RETURN_SUCCESSBREAK 0 |
#define FEATURE_SENSE_CHAN (1 << 0) |
Definition at line 546 of file res_features.c.
Referenced by ast_bridge_call(), ast_feature_interpret(), cmd_atxfer(), and feature_exec_app().
#define FEATURE_SENSE_PEER (1 << 1) |
Definition at line 547 of file res_features.c.
Referenced by ast_bridge_call(), cmd_atxfer(), and set_peers().
#define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0])) |
Definition at line 1030 of file res_features.c.
Referenced by ast_feature_interpret(), ast_feature_request_and_dial(), handle_showfeatures(), remap_feature(), set_config_flags(), and unmap_features().
anonymous enum |
AST_FEATURE_FLAG_NEEDSDTMF | |
AST_FEATURE_FLAG_ONPEER | |
AST_FEATURE_FLAG_ONSELF | |
AST_FEATURE_FLAG_BYCALLEE | |
AST_FEATURE_FLAG_BYCALLER | |
AST_FEATURE_FLAG_BYBOTH |
Definition at line 74 of file res_features.c.
00074 { 00075 AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0), 00076 AST_FEATURE_FLAG_ONPEER = (1 << 1), 00077 AST_FEATURE_FLAG_ONSELF = (1 << 2), 00078 AST_FEATURE_FLAG_BYCALLEE = (1 << 3), 00079 AST_FEATURE_FLAG_BYCALLER = (1 << 4), 00080 AST_FEATURE_FLAG_BYBOTH = (3 << 3), 00081 };
static void __reg_module | ( | void | ) | [static] |
Definition at line 2811 of file res_features.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 2811 of file res_features.c.
static int adsi_announce_park | ( | struct ast_channel * | chan, | |
char * | parkingexten | |||
) | [static] |
Definition at line 257 of file res_features.c.
References ADSI_JUST_CENT, ast_adsi_load_session(), ast_adsi_print(), and justify.
Referenced by park_call_full().
00258 { 00259 int res; 00260 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT}; 00261 char tmp[256]; 00262 char *message[5] = {NULL, NULL, NULL, NULL, NULL}; 00263 00264 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten); 00265 message[0] = tmp; 00266 res = ast_adsi_load_session(chan, NULL, 0, 1); 00267 if (res == -1) 00268 return res; 00269 return ast_adsi_print(chan, message, justify, 1); 00270 }
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 1477 of file res_features.c.
References ast_channel::_state, ast_channel::accountcode, ast_cdr::accountcode, ast_channel::amaflags, ast_cdr::amaflags, ast_cdr::answer, ast_channel::appl, ast_answer(), ast_bridged_channel(), ast_cdr_alloc(), ast_cdr_answer(), AST_CDR_ANSWERED, ast_cdr_detach(), ast_cdr_dup(), ast_cdr_end(), AST_CDR_FLAG_BRIDGED, AST_CDR_FLAG_MAIN, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NULL, ast_cdr_setcid(), ast_cdr_specialized_reset(), ast_cdr_start(), ast_cdr_update(), ast_channel_bridge(), ast_channel_lock, ast_channel_setoption(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, AST_CONTROL_ATXFERCMD, 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_copy_string(), ast_default_amaflags, ast_dtmf_stream(), ast_exists_extension(), ast_feature_interpret(), AST_FEATURE_NO_H_EXTEN, AST_FEATURE_PLAY_WARNING, AST_FLAG_BRIDGE_HANGUP_RUN, AST_FLAG_IN_AUTOLOOP, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, ast_frfree, ast_get_channel_by_name_locked(), ast_indicate(), ast_indicate_data(), ast_log(), AST_MAX_EXTENSION, ast_opt_end_cdr_before_h_exten, AST_OPTION_FLAG_REQUEST, ast_set2_flag, ast_set_flag, ast_spawn_extension(), AST_STATE_RINGING, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), ast_verbose(), ast_channel::cdr, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, cmd_atxfer(), config, ast_channel::context, ast_option_header::data, ast_channel::data, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_channel::exten, f, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_option_header::flag, ast_cdr::lastapp, ast_cdr::lastdata, LOG_DEBUG, LOG_WARNING, monitor_app, ast_channel::name, ast_cdr::next, ast_option_header::option, option_debug, option_verbose, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pick_unlocked_cdr(), ast_channel::priority, set_config_flags(), ast_cdr::start, ast_channel::uniqueid, ast_cdr::uniqueid, ast_cdr::userfield, VERBOSE_PREFIX_2, and ast_channel::visible_indication.
Referenced by app_exec(), ast_bridge_call_thread(), do_atxfer(), park_exec(), and try_calling().
01478 { 01479 /* Copy voice back and forth between the two channels. Give the peer 01480 the ability to transfer calls with '#<extension' syntax. */ 01481 struct ast_frame *f; 01482 struct ast_channel *who; 01483 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 01484 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 01485 char orig_channame[AST_MAX_EXTENSION]; 01486 char orig_peername[AST_MAX_EXTENSION]; 01487 01488 int res; 01489 int diff; 01490 int hasfeatures=0; 01491 int hadfeatures=0; 01492 int autoloopflag; 01493 struct ast_option_header *aoh; 01494 struct ast_bridge_config backup_config; 01495 struct ast_cdr *bridge_cdr = NULL; 01496 struct ast_cdr *orig_peer_cdr = NULL; 01497 struct ast_cdr *chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 01498 struct ast_cdr *peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 01499 struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 01500 struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 01501 01502 memset(&backup_config, 0, sizeof(backup_config)); 01503 01504 config->start_time = ast_tvnow(); 01505 01506 if (chan && peer) { 01507 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 01508 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 01509 } else if (chan) { 01510 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 01511 } 01512 01513 /* This is an interesting case. One example is if a ringing channel gets redirected to 01514 * an extension that picks up a parked call. This will make sure that the call taken 01515 * out of parking gets told that the channel it just got bridged to is still ringing. */ 01516 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) { 01517 ast_indicate(peer, AST_CONTROL_RINGING); 01518 } 01519 01520 if (monitor_ok) { 01521 const char *monitor_exec; 01522 struct ast_channel *src = NULL; 01523 if (!monitor_app) { 01524 if (!(monitor_app = pbx_findapp("Monitor"))) 01525 monitor_ok=0; 01526 } 01527 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 01528 src = chan; 01529 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 01530 src = peer; 01531 if (monitor_app && src) { 01532 char *tmp = ast_strdupa(monitor_exec); 01533 pbx_exec(src, monitor_app, tmp); 01534 } 01535 } 01536 01537 set_config_flags(chan, peer, config); 01538 config->firstpass = 1; 01539 01540 /* Answer if need be */ 01541 if (ast_answer(chan)) 01542 return -1; 01543 01544 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame)); 01545 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername)); 01546 orig_peer_cdr = peer_cdr; 01547 01548 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) { 01549 01550 if (chan_cdr) { 01551 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN); 01552 ast_cdr_update(chan); 01553 bridge_cdr = ast_cdr_dup(chan_cdr); 01554 ast_copy_string(bridge_cdr->lastapp, chan->appl, sizeof(bridge_cdr->lastapp)); 01555 ast_copy_string(bridge_cdr->lastdata, chan->data, sizeof(bridge_cdr->lastdata)); 01556 } else { 01557 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 01558 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 01559 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel)); 01560 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel)); 01561 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid)); 01562 ast_copy_string(bridge_cdr->lastapp, chan->appl, sizeof(bridge_cdr->lastapp)); 01563 ast_copy_string(bridge_cdr->lastdata, chan->data, sizeof(bridge_cdr->lastdata)); 01564 ast_cdr_setcid(bridge_cdr, chan); 01565 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL; 01566 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags; 01567 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode)); 01568 /* Destination information */ 01569 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst)); 01570 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext)); 01571 if (peer_cdr) { 01572 bridge_cdr->start = peer_cdr->start; 01573 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 01574 } else { 01575 ast_cdr_start(bridge_cdr); 01576 } 01577 } 01578 /* peer_cdr->answer will be set when a macro runs on the peer; 01579 in that case, the bridge answer will be delayed while the 01580 macro plays on the peer channel. The peer answered the call 01581 before the macro started playing. To the phone system, 01582 this is billable time for the call, even tho the caller 01583 hears nothing but ringing while the macro does its thing. */ 01584 if (peer_cdr && !ast_tvzero(peer_cdr->answer)) { 01585 bridge_cdr->answer = peer_cdr->answer; 01586 chan_cdr->answer = peer_cdr->answer; 01587 bridge_cdr->disposition = peer_cdr->disposition; 01588 chan_cdr->disposition = peer_cdr->disposition; 01589 } else { 01590 ast_cdr_answer(bridge_cdr); 01591 ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */ 01592 } 01593 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED); 01594 if (peer_cdr) { 01595 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED); 01596 } 01597 } 01598 01599 for (;;) { 01600 struct ast_channel *other; /* used later */ 01601 01602 res = ast_channel_bridge(chan, peer, config, &f, &who); 01603 01604 if (config->feature_timer) { 01605 /* Update time limit for next pass */ 01606 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time); 01607 config->feature_timer -= diff; 01608 if (hasfeatures) { 01609 /* Running on backup config, meaning a feature might be being 01610 activated, but that's no excuse to keep things going 01611 indefinitely! */ 01612 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) { 01613 if (option_debug) 01614 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n"); 01615 config->feature_timer = 0; 01616 who = chan; 01617 if (f) 01618 ast_frfree(f); 01619 f = NULL; 01620 res = 0; 01621 } else if (config->feature_timer <= 0) { 01622 /* Not *really* out of time, just out of time for 01623 digits to come in for features. */ 01624 if (option_debug) 01625 ast_log(LOG_DEBUG, "Timed out for feature!\n"); 01626 if (!ast_strlen_zero(peer_featurecode)) { 01627 ast_dtmf_stream(chan, peer, peer_featurecode, 0); 01628 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 01629 } 01630 if (!ast_strlen_zero(chan_featurecode)) { 01631 ast_dtmf_stream(peer, chan, chan_featurecode, 0); 01632 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 01633 } 01634 if (f) 01635 ast_frfree(f); 01636 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01637 if (!hasfeatures) { 01638 /* Restore original (possibly time modified) bridge config */ 01639 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01640 memset(&backup_config, 0, sizeof(backup_config)); 01641 } 01642 hadfeatures = hasfeatures; 01643 /* Continue as we were */ 01644 continue; 01645 } else if (!f) { 01646 /* The bridge returned without a frame and there is a feature in progress. 01647 * However, we don't think the feature has quite yet timed out, so just 01648 * go back into the bridge. */ 01649 continue; 01650 } 01651 } else { 01652 if (config->feature_timer <=0) { 01653 /* We ran out of time */ 01654 config->feature_timer = 0; 01655 who = chan; 01656 if (f) 01657 ast_frfree(f); 01658 f = NULL; 01659 res = 0; 01660 } 01661 } 01662 } 01663 if (res < 0) { 01664 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) 01665 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 01666 goto before_you_go; 01667 } 01668 01669 if (!f || (f->frametype == AST_FRAME_CONTROL && 01670 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 01671 f->subclass == AST_CONTROL_CONGESTION ) ) ) { 01672 res = -1; 01673 break; 01674 } 01675 /* many things should be sent to the 'other' channel */ 01676 other = (who == chan) ? peer : chan; 01677 if (f->frametype == AST_FRAME_CONTROL) { 01678 switch (f->subclass) { 01679 case AST_CONTROL_RINGING: 01680 case AST_CONTROL_FLASH: 01681 case -1: 01682 ast_indicate(other, f->subclass); 01683 break; 01684 case AST_CONTROL_HOLD: 01685 case AST_CONTROL_UNHOLD: 01686 ast_indicate_data(other, f->subclass, f->data, f->datalen); 01687 break; 01688 case AST_CONTROL_OPTION: 01689 aoh = f->data; 01690 /* Forward option Requests */ 01691 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 01692 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 01693 f->datalen - sizeof(struct ast_option_header), 0); 01694 } 01695 break; 01696 case AST_CONTROL_ATXFERCMD: 01697 cmd_atxfer(chan, peer, config, who, f->data); 01698 break; 01699 } 01700 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 01701 /* eat it */ 01702 } else if (f->frametype == AST_FRAME_DTMF) { 01703 char *featurecode; 01704 int sense; 01705 01706 hadfeatures = hasfeatures; 01707 /* This cannot overrun because the longest feature is one shorter than our buffer */ 01708 if (who == chan) { 01709 sense = FEATURE_SENSE_CHAN; 01710 featurecode = chan_featurecode; 01711 } else { 01712 sense = FEATURE_SENSE_PEER; 01713 featurecode = peer_featurecode; 01714 } 01715 /*! append the event to featurecode. we rely on the string being zero-filled, and 01716 * not overflowing it. 01717 * \todo XXX how do we guarantee the latter ? 01718 */ 01719 featurecode[strlen(featurecode)] = f->subclass; 01720 /* Get rid of the frame before we start doing "stuff" with the channels */ 01721 ast_frfree(f); 01722 f = NULL; 01723 config->feature_timer = backup_config.feature_timer; 01724 res = ast_feature_interpret(chan, peer, config, featurecode, sense); 01725 switch(res) { 01726 case FEATURE_RETURN_PASSDIGITS: 01727 ast_dtmf_stream(other, who, featurecode, 0); 01728 /* Fall through */ 01729 case FEATURE_RETURN_SUCCESS: 01730 memset(featurecode, 0, sizeof(chan_featurecode)); 01731 break; 01732 } 01733 if (res >= FEATURE_RETURN_PASSDIGITS) { 01734 res = 0; 01735 } else 01736 break; 01737 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01738 if (hadfeatures && !hasfeatures) { 01739 /* Restore backup */ 01740 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01741 memset(&backup_config, 0, sizeof(struct ast_bridge_config)); 01742 } else if (hasfeatures) { 01743 if (!hadfeatures) { 01744 /* Backup configuration */ 01745 memcpy(&backup_config, config, sizeof(struct ast_bridge_config)); 01746 /* Setup temporary config options */ 01747 config->play_warning = 0; 01748 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 01749 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 01750 config->warning_freq = 0; 01751 config->warning_sound = NULL; 01752 config->end_sound = NULL; 01753 config->start_sound = NULL; 01754 config->firstpass = 0; 01755 } 01756 config->start_time = ast_tvnow(); 01757 config->feature_timer = featuredigittimeout; 01758 if (option_debug) 01759 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer); 01760 } 01761 } 01762 if (f) 01763 ast_frfree(f); 01764 01765 } 01766 before_you_go: 01767 if (config->end_bridge_callback) { 01768 config->end_bridge_callback(config->end_bridge_callback_data); 01769 } 01770 01771 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP); 01772 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP); 01773 if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) && ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) { 01774 struct ast_cdr *swapper = NULL; 01775 char savelastapp[AST_MAX_EXTENSION]; 01776 char savelastdata[AST_MAX_EXTENSION]; 01777 char save_exten[AST_MAX_EXTENSION]; 01778 int save_prio; 01779 01780 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) { 01781 ast_cdr_end(bridge_cdr); 01782 } 01783 /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge 01784 dialplan code operate on it */ 01785 ast_channel_lock(chan); 01786 if (bridge_cdr) { 01787 swapper = chan->cdr; 01788 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp)); 01789 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata)); 01790 chan->cdr = bridge_cdr; 01791 } 01792 ast_copy_string(save_exten, chan->exten, sizeof(save_exten)); 01793 ast_copy_string(chan->exten, "h", sizeof(chan->exten)); 01794 save_prio = chan->priority; 01795 chan->priority = 1; 01796 ast_channel_unlock(chan); 01797 while(ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) { 01798 if (ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) { 01799 /* Something bad happened, or a hangup has been requested. */ 01800 if (option_debug) 01801 ast_log(LOG_DEBUG, "Spawn h extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 01802 if (option_verbose > 1) 01803 ast_verbose( VERBOSE_PREFIX_2 "Spawn h extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 01804 break; 01805 } 01806 chan->priority++; 01807 } 01808 /* swap it back */ 01809 ast_channel_lock(chan); 01810 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten)); 01811 chan->priority = save_prio; 01812 if (bridge_cdr) 01813 chan->cdr = swapper; 01814 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN); 01815 ast_channel_unlock(chan); 01816 /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */ 01817 if (bridge_cdr) { 01818 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp)); 01819 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata)); 01820 } 01821 } 01822 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP); 01823 01824 /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */ 01825 new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 01826 if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) { 01827 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED); 01828 } 01829 01830 /* we can post the bridge CDR at this point */ 01831 if (bridge_cdr) { 01832 ast_cdr_end(bridge_cdr); 01833 ast_cdr_detach(bridge_cdr); 01834 } 01835 01836 /* do a specialized reset on the beginning channel 01837 CDR's, if they still exist, so as not to mess up 01838 issues in future bridges; 01839 01840 Here are the rules of the game: 01841 1. The chan and peer channel pointers will not change 01842 during the life of the bridge. 01843 2. But, in transfers, the channel names will change. 01844 between the time the bridge is started, and the 01845 time the channel ends. 01846 Usually, when a channel changes names, it will 01847 also change CDR pointers. 01848 3. Usually, only one of the two channels (chan or peer) 01849 will change names. 01850 4. Usually, if a channel changes names during a bridge, 01851 it is because of a transfer. Usually, in these situations, 01852 it is normal to see 2 bridges running simultaneously, and 01853 it is not unusual to see the two channels that change 01854 swapped between bridges. 01855 5. After a bridge occurs, we have 2 or 3 channels' CDRs 01856 to attend to; if the chan or peer changed names, 01857 we have the before and after attached CDR's. 01858 */ 01859 01860 if (new_chan_cdr) { 01861 struct ast_channel *chan_ptr = NULL; 01862 01863 if (strcasecmp(orig_channame, chan->name) != 0) { 01864 /* old channel */ 01865 chan_ptr = ast_get_channel_by_name_locked(orig_channame); 01866 if (chan_ptr) { 01867 if (!ast_bridged_channel(chan_ptr)) { 01868 struct ast_cdr *cur; 01869 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 01870 if (cur == chan_cdr) { 01871 break; 01872 } 01873 } 01874 if (cur) 01875 ast_cdr_specialized_reset(chan_cdr,0); 01876 } 01877 ast_channel_unlock(chan_ptr); 01878 } 01879 /* new channel */ 01880 ast_cdr_specialized_reset(new_chan_cdr,0); 01881 } else { 01882 ast_cdr_specialized_reset(chan_cdr,0); /* nothing changed, reset the chan_cdr */ 01883 } 01884 } 01885 01886 { 01887 struct ast_channel *chan_ptr = NULL; 01888 new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 01889 if (new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED) && new_peer_cdr && !ast_test_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED)) 01890 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */ 01891 if (strcasecmp(orig_peername, peer->name) != 0) { 01892 /* old channel */ 01893 chan_ptr = ast_get_channel_by_name_locked(orig_peername); 01894 if (chan_ptr) { 01895 if (!ast_bridged_channel(chan_ptr)) { 01896 struct ast_cdr *cur; 01897 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 01898 if (cur == peer_cdr) { 01899 break; 01900 } 01901 } 01902 if (cur) 01903 ast_cdr_specialized_reset(peer_cdr,0); 01904 } 01905 ast_channel_unlock(chan_ptr); 01906 } 01907 /* new channel */ 01908 ast_cdr_specialized_reset(new_peer_cdr,0); 01909 } else { 01910 ast_cdr_specialized_reset(peer_cdr,0); /* nothing changed, reset the peer_cdr */ 01911 } 01912 } 01913 return res; 01914 }
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_hangup(), ast_bridge_thread_obj::bconfig, ast_bridge_thread_obj::chan, ast_channel::data, free, ast_channel::name, and ast_bridge_thread_obj::peer.
Referenced by ast_bridge_call_thread_launch().
00227 { 00228 struct ast_bridge_thread_obj *tobj = data; 00229 00230 tobj->chan->appl = "Transferred Call"; 00231 tobj->chan->data = tobj->peer->name; 00232 tobj->peer->appl = "Transferred Call"; 00233 tobj->peer->data = tobj->chan->name; 00234 00235 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig); 00236 ast_hangup(tobj->chan); 00237 ast_hangup(tobj->peer); 00238 bzero(tobj, sizeof(*tobj)); /*! \todo XXX for safety */ 00239 free(tobj); 00240 return NULL; 00241 }
static void ast_bridge_call_thread_launch | ( | void * | data | ) | [static] |
Definition at line 243 of file res_features.c.
References ast_bridge_call_thread(), ast_pthread_create, and thread.
Referenced by do_atxfer().
00244 { 00245 pthread_t thread; 00246 pthread_attr_t attr; 00247 struct sched_param sched; 00248 00249 pthread_attr_init(&attr); 00250 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 00251 ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data); 00252 pthread_attr_destroy(&attr); 00253 memset(&sched, 0, sizeof(sched)); 00254 pthread_setschedparam(thread, SCHED_RR, &sched); 00255 }
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 1188 of file res_features.c.
References ast_copy_flags, AST_FLAGS_ALL, ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, 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, features_lock, find_dynamic_feature(), ast_flags::flags, LOG_DEBUG, ast_channel::name, ast_call_feature::operation, option_debug, option_verbose, pbx_builtin_getvar_helper(), ast_call_feature::sname, and VERBOSE_PREFIX_3.
Referenced by ast_bridge_call().
01189 { 01190 int x; 01191 struct ast_flags features; 01192 struct ast_call_feature *feature; 01193 const char *dynamic_features; 01194 char *tmp, *tok; 01195 int res = FEATURE_RETURN_PASSDIGITS; 01196 int feature_detected = 0; 01197 01198 if (sense == FEATURE_SENSE_CHAN) { 01199 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL); 01200 dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"); 01201 } else { 01202 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL); 01203 dynamic_features = pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"); 01204 } 01205 if (option_debug > 2) 01206 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); 01207 01208 ast_rwlock_rdlock(&features_lock); 01209 for (x = 0; x < FEATURES_COUNT; x++) { 01210 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) && 01211 !ast_strlen_zero(builtin_features[x].exten)) { 01212 /* Feature is up for consideration */ 01213 if (!strcmp(builtin_features[x].exten, code)) { 01214 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL); 01215 feature_detected = 1; 01216 break; 01217 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) { 01218 if (res == FEATURE_RETURN_PASSDIGITS) 01219 res = FEATURE_RETURN_STOREDIGITS; 01220 } 01221 } 01222 } 01223 ast_rwlock_unlock(&features_lock); 01224 01225 if (ast_strlen_zero(dynamic_features) || feature_detected) 01226 return res; 01227 01228 tmp = ast_strdupa(dynamic_features); 01229 01230 while ((tok = strsep(&tmp, "#"))) { 01231 AST_RWLIST_RDLOCK(&feature_list); 01232 if (!(feature = find_dynamic_feature(tok))) { 01233 AST_RWLIST_UNLOCK(&feature_list); 01234 continue; 01235 } 01236 01237 /* Feature is up for consideration */ 01238 if (!strcmp(feature->exten, code)) { 01239 if (option_verbose > 2) 01240 ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok); 01241 res = feature->operation(chan, peer, config, code, sense, feature); 01242 if (res != FEATURE_RETURN_KEEPTRYING) { 01243 AST_RWLIST_UNLOCK(&feature_list); 01244 break; 01245 } 01246 res = FEATURE_RETURN_PASSDIGITS; 01247 } else if (!strncmp(feature->exten, code, strlen(code))) 01248 res = FEATURE_RETURN_STOREDIGITS; 01249 01250 AST_RWLIST_UNLOCK(&feature_list); 01251 } 01252 01253 return res; 01254 }
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 1299 of file res_features.c.
References ast_channel::_softhangup, ast_channel::_state, ast_call(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, 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_tvdiff_ms(), ast_tvnow(), ast_verbose(), ast_waitfor_n(), builtin_features, ast_call_feature::exten, f, FEATURES_COUNT, features_lock, len(), LOG_NOTICE, ast_channel::name, option_verbose, pbx_builtin_setvar_helper(), and VERBOSE_PREFIX_3.
Referenced by do_atxfer().
01300 { 01301 int state = 0; 01302 int cause = 0; 01303 int to; 01304 struct ast_channel *chan; 01305 struct ast_channel *monitor_chans[2]; 01306 struct ast_channel *active_channel; 01307 int res = 0, ready = 0; 01308 01309 if ((chan = ast_request(type, format, data, &cause))) { 01310 ast_set_callerid(chan, cid_num, cid_name, cid_num); 01311 ast_string_field_set(chan, language, language); 01312 ast_channel_inherit_variables(caller, chan); 01313 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name); 01314 01315 if (!ast_call(chan, data, timeout)) { 01316 struct timeval started; 01317 int x, len = 0; 01318 char *disconnect_code = NULL, *dialed_code = NULL; 01319 01320 ast_indicate(caller, AST_CONTROL_RINGING); 01321 /* support dialing of the featuremap disconnect code while performing an attended tranfer */ 01322 ast_rwlock_rdlock(&features_lock); 01323 for (x = 0; x < FEATURES_COUNT; x++) { 01324 if (strcasecmp(builtin_features[x].sname, "disconnect")) 01325 continue; 01326 01327 disconnect_code = builtin_features[x].exten; 01328 len = strlen(disconnect_code) + 1; 01329 dialed_code = alloca(len); 01330 memset(dialed_code, 0, len); 01331 break; 01332 } 01333 ast_rwlock_unlock(&features_lock); 01334 x = 0; 01335 started = ast_tvnow(); 01336 to = timeout; 01337 while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) { 01338 struct ast_frame *f = NULL; 01339 01340 monitor_chans[0] = caller; 01341 monitor_chans[1] = chan; 01342 active_channel = ast_waitfor_n(monitor_chans, 2, &to); 01343 01344 /* see if the timeout has been violated */ 01345 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) { 01346 state = AST_CONTROL_UNHOLD; 01347 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n"); 01348 break; /*doh! timeout*/ 01349 } 01350 01351 if (!active_channel) 01352 continue; 01353 01354 if (chan && (chan == active_channel)){ 01355 f = ast_read(chan); 01356 if (f == NULL) { /*doh! where'd he go?*/ 01357 state = AST_CONTROL_HANGUP; 01358 res = 0; 01359 break; 01360 } 01361 01362 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) { 01363 if (f->subclass == AST_CONTROL_RINGING) { 01364 state = f->subclass; 01365 if (option_verbose > 2) 01366 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name); 01367 ast_indicate(caller, AST_CONTROL_RINGING); 01368 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) { 01369 state = f->subclass; 01370 if (option_verbose > 2) 01371 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name); 01372 ast_indicate(caller, AST_CONTROL_BUSY); 01373 ast_frfree(f); 01374 f = NULL; 01375 break; 01376 } else if (f->subclass == AST_CONTROL_ANSWER) { 01377 /* This is what we are hoping for */ 01378 state = f->subclass; 01379 ast_frfree(f); 01380 f = NULL; 01381 ready=1; 01382 break; 01383 } else if (f->subclass != -1) { 01384 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass); 01385 } 01386 /* else who cares */ 01387 } 01388 01389 } else if (caller && (active_channel == caller)) { 01390 f = ast_read(caller); 01391 if (f == NULL) { /*doh! where'd he go?*/ 01392 if (caller->_softhangup && !chan->_softhangup) { 01393 /* make this a blind transfer */ 01394 ready = 1; 01395 break; 01396 } 01397 state = AST_CONTROL_HANGUP; 01398 res = 0; 01399 break; 01400 } 01401 01402 if (f->frametype == AST_FRAME_DTMF) { 01403 dialed_code[x++] = f->subclass; 01404 dialed_code[x] = '\0'; 01405 if (strlen(dialed_code) == len) { 01406 x = 0; 01407 } else if (x && strncmp(dialed_code, disconnect_code, x)) { 01408 x = 0; 01409 dialed_code[x] = '\0'; 01410 } 01411 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) { 01412 /* Caller Canceled the call */ 01413 state = AST_CONTROL_UNHOLD; 01414 ast_frfree(f); 01415 f = NULL; 01416 break; 01417 } 01418 } 01419 } 01420 if (f) 01421 ast_frfree(f); 01422 } /* end while */ 01423 } else 01424 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data); 01425 } else { 01426 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data); 01427 switch(cause) { 01428 case AST_CAUSE_BUSY: 01429 state = AST_CONTROL_BUSY; 01430 break; 01431 case AST_CAUSE_CONGESTION: 01432 state = AST_CONTROL_CONGESTION; 01433 break; 01434 } 01435 } 01436 01437 ast_indicate(caller, -1); 01438 if (chan && ready) { 01439 if (chan->_state == AST_STATE_UP) 01440 state = AST_CONTROL_ANSWER; 01441 res = 0; 01442 } else if(chan) { 01443 res = -1; 01444 ast_hangup(chan); 01445 chan = NULL; 01446 } else { 01447 res = -1; 01448 } 01449 01450 if (outstate) 01451 *outstate = state; 01452 01453 return chan; 01454 }
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 530 of file res_features.c.
References masq_park_call().
Referenced by handle_exec(), manager_park(), mgcp_ss(), parkandannounce_exec(), and ss_thread().
00531 { 00532 return masq_park_call(rchan, peer, timeout, extout, 0, NULL); 00533 }
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 482 of file res_features.c.
References park_call_full().
Referenced by iax_park_thread(), and sip_park_thread().
00483 { 00484 return park_call_full(chan, peer, timeout, extout, NULL); 00485 }
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 162 of file res_features.c.
Referenced by builtin_blindtransfer(), dp_lookup(), handle_request_refer(), mgcp_ss(), socket_process(), and ss_thread().
00163 { 00164 return parking_ext; 00165 }
int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
Definition at line 2494 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, ast_channel::name, option_debug, ast_channel::pbx, and ast_channel::pickupgroup.
Referenced by cb_events(), handle_request_invite(), mgcp_ss(), and ss_thread().
02495 { 02496 struct ast_channel *cur = NULL; 02497 int res = -1; 02498 02499 while ( (cur = ast_channel_walk_locked(cur)) != NULL) { 02500 if (!cur->pbx && 02501 (cur != chan) && 02502 (chan->pickupgroup & cur->callgroup) && 02503 ((cur->_state == AST_STATE_RINGING) || 02504 (cur->_state == AST_STATE_RING))) { 02505 break; 02506 } 02507 ast_channel_unlock(cur); 02508 } 02509 if (cur) { 02510 if (option_debug) 02511 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name); 02512 res = ast_answer(chan); 02513 if (res) 02514 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); 02515 res = ast_queue_control(chan, AST_CONTROL_ANSWER); 02516 if (res) 02517 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); 02518 res = ast_channel_masquerade(cur, chan); 02519 if (res) 02520 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */ 02521 ast_channel_unlock(cur); 02522 } else { 02523 if (option_debug) 02524 ast_log(LOG_DEBUG, "No call pickup possible...\n"); 02525 } 02526 return res; 02527 }
char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 167 of file res_features.c.
Referenced by cb_events(), get_destination(), handle_request_invite(), handle_showfeatures(), mgcp_ss(), and ss_thread().
00168 { 00169 return pickup_ext; 00170 }
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 1047 of file res_features.c.
References ast_log(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verbose(), ast_call_feature::feature_entry, LOG_NOTICE, option_verbose, ast_call_feature::sname, and VERBOSE_PREFIX_2.
01048 { 01049 if (!feature) { 01050 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 01051 return; 01052 } 01053 01054 AST_RWLIST_WRLOCK(&feature_list); 01055 AST_RWLIST_INSERT_HEAD(&feature_list, feature, feature_entry); 01056 AST_RWLIST_UNLOCK(&feature_list); 01057 01058 if (option_verbose >= 2) { 01059 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname); 01060 } 01061 }
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 1064 of file res_features.c.
References AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_call_feature::feature_entry, and free.
01065 { 01066 if (!feature) 01067 return; 01068 01069 AST_RWLIST_WRLOCK(&feature_list); 01070 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry); 01071 AST_RWLIST_UNLOCK(&feature_list); 01072 01073 free(feature); 01074 }
static void ast_unregister_features | ( | void | ) | [static] |
Remove all features in the list.
Definition at line 1077 of file res_features.c.
References AST_LIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_call_feature::feature_entry, and free.
01078 { 01079 struct ast_call_feature *feature; 01080 01081 AST_RWLIST_WRLOCK(&feature_list); 01082 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list, feature_entry))) { 01083 free(feature); 01084 } 01085 AST_RWLIST_UNLOCK(&feature_list); 01086 }
static int builtin_atxfer | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
char * | code, | |||
int | sense, | |||
void * | data | |||
) | [static] |
Attended transfer ().
chan | ||
peer | ||
config | ||
code | ||
sense | ||
data | Get extension to transfer to, if you cannot generate channel (or find extension) return to host channel. After called channel answered wait for hangup of transferer, bridge call between transfer peer (taking them off hold) to attended transfer channel. |
Definition at line 1024 of file res_features.c.
References config, and do_atxfer().
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 600 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, ast_channel::language, len(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_channel::monitor, monitor_app, ast_channel::name, option_verbose, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), S_OR, set_peers(), and VERBOSE_PREFIX_3.
00601 { 00602 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 00603 int x = 0; 00604 size_t len; 00605 struct ast_channel *caller_chan, *callee_chan; 00606 00607 if (!monitor_ok) { 00608 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 00609 return -1; 00610 } 00611 00612 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) { 00613 monitor_ok = 0; 00614 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 00615 return -1; 00616 } 00617 00618 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 00619 00620 if (!ast_strlen_zero(courtesytone)) { 00621 if (ast_autoservice_start(callee_chan)) 00622 return -1; 00623 if (ast_stream_and_wait(caller_chan, courtesytone, caller_chan->language, "")) { 00624 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 00625 ast_autoservice_stop(callee_chan); 00626 return -1; 00627 } 00628 if (ast_autoservice_stop(callee_chan)) 00629 return -1; 00630 } 00631 00632 if (callee_chan->monitor) { 00633 if (option_verbose > 3) 00634 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code); 00635 ast_monitor_stop(callee_chan, 1); 00636 return FEATURE_RETURN_SUCCESS; 00637 } 00638 00639 if (caller_chan && callee_chan) { 00640 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT"); 00641 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR"); 00642 00643 if (!touch_format) 00644 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT"); 00645 00646 if (!touch_monitor) 00647 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR"); 00648 00649 if (touch_monitor) { 00650 len = strlen(touch_monitor) + 50; 00651 args = alloca(len); 00652 touch_filename = alloca(len); 00653 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor); 00654 snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename); 00655 } else { 00656 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name)); 00657 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name)); 00658 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 00659 args = alloca(len); 00660 touch_filename = alloca(len); 00661 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id); 00662 snprintf(args, len, "%s|%s|m", S_OR(touch_format, "wav"), touch_filename); 00663 } 00664 00665 for( x = 0; x < strlen(args); x++) { 00666 if (args[x] == '/') 00667 args[x] = '-'; 00668 } 00669 00670 if (option_verbose > 3) 00671 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args); 00672 00673 pbx_exec(callee_chan, monitor_app, args); 00674 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 00675 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 00676 00677 return FEATURE_RETURN_SUCCESS; 00678 } 00679 00680 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); 00681 return -1; 00682 }
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 711 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_parking_ext(), ast_stopstream(), ast_strdupa, ast_stream_and_wait(), ast_verbose(), check_goto_on_transfer(), ast_channel::cid, ast_callerid::cid_num, FEATURE_RETURN_SUCCESS, finishup(), ast_channel::language, LOG_WARNING, masq_park_call_announce(), ast_channel::name, option_verbose, ast_channel::pbx, pbx_builtin_setvar_helper(), real_ctx(), set_c_e_p(), set_peers(), VERBOSE_PREFIX_2, and VERBOSE_PREFIX_3.
00712 { 00713 struct ast_channel *transferer; 00714 struct ast_channel *transferee; 00715 const char *transferer_real_context; 00716 char xferto[256]; 00717 int res; 00718 const char *orig_chan_name; 00719 00720 set_peers(&transferer, &transferee, peer, chan, sense); 00721 orig_chan_name = ast_strdupa(transferer->name); 00722 transferer_real_context = real_ctx(transferer, transferee); 00723 /* Start autoservice on chan while we talk to the originator */ 00724 ast_autoservice_start(transferee); 00725 ast_indicate(transferee, AST_CONTROL_HOLD); 00726 00727 memset(xferto, 0, sizeof(xferto)); 00728 00729 /* Transfer */ 00730 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY); 00731 if (res < 0) { 00732 finishup(transferee); 00733 return -1; /* error ? */ 00734 } 00735 if (res > 0) /* If they've typed a digit already, handle it */ 00736 xferto[0] = (char) res; 00737 00738 ast_stopstream(transferer); 00739 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 00740 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */ 00741 finishup(transferee); 00742 return res; 00743 } 00744 if (!strcmp(xferto, ast_parking_ext())) { 00745 res = finishup(transferee); 00746 if (res) 00747 res = -1; 00748 else if (!masq_park_call_announce(transferee, transferer, 0, NULL, orig_chan_name)) { /* success */ 00749 /* We return non-zero, but tell the PBX not to hang the channel when 00750 the thread dies -- We have to be careful now though. We are responsible for 00751 hanging up the channel, else it will never be hung up! */ 00752 return 0; 00753 } else { 00754 ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name); 00755 } 00756 /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */ 00757 } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) { 00758 pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name); 00759 pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name); 00760 res=finishup(transferee); 00761 if (!transferer->cdr) { 00762 transferer->cdr=ast_cdr_alloc(); 00763 if (transferer) { 00764 ast_cdr_init(transferer->cdr, transferer); /* initilize our channel's cdr */ 00765 ast_cdr_start(transferer->cdr); 00766 } 00767 } 00768 if (transferer->cdr) { 00769 ast_cdr_setdestchan(transferer->cdr, transferee->name); 00770 ast_cdr_setapp(transferer->cdr, "BLINDTRANSFER",""); 00771 } 00772 if (!transferee->pbx) { 00773 /* Doh! Use our handy async_goto functions */ 00774 if (option_verbose > 2) 00775 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n" 00776 ,transferee->name, xferto, transferer_real_context); 00777 if (ast_async_goto(transferee, transferer_real_context, xferto, 1)) 00778 ast_log(LOG_WARNING, "Async goto failed :-(\n"); 00779 res = -1; 00780 } else { 00781 /* Set the channel's new extension, since it exists, using transferer context */ 00782 set_c_e_p(transferee, transferer_real_context, xferto, 0); 00783 } 00784 check_goto_on_transfer(transferer); 00785 return res; 00786 } else { 00787 if (option_verbose > 2) 00788 ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context); 00789 } 00790 if (ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0 ) { 00791 finishup(transferee); 00792 return -1; 00793 } 00794 ast_stopstream(transferer); 00795 res = finishup(transferee); 00796 if (res) { 00797 if (option_verbose > 1) 00798 ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name); 00799 return res; 00800 } 00801 return FEATURE_RETURN_SUCCESS; 00802 }
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 684 of file res_features.c.
References ast_verbose(), FEATURE_RETURN_HANGUP, option_verbose, and VERBOSE_PREFIX_3.
00685 { 00686 if (option_verbose > 3) 00687 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code); 00688 return FEATURE_RETURN_HANGUP; 00689 }
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 565 of file res_features.c.
References ast_channel::_state, ast_answer(), ast_module_user_add, ast_module_user_remove, ast_safe_sleep(), AST_STATE_UP, ast_strdupa, ast_module_user::chan, masq_park_call_announce(), ast_channel::name, and set_peers().
00566 { 00567 struct ast_channel *parker; 00568 struct ast_channel *parkee; 00569 int res = 0; 00570 struct ast_module_user *u; 00571 const char *orig_chan_name; 00572 00573 u = ast_module_user_add(chan); 00574 00575 set_peers(&parker, &parkee, peer, chan, sense); 00576 orig_chan_name = ast_strdupa(parker->name); 00577 /* we used to set chan's exten and priority to "s" and 1 00578 here, but this generates (in some cases) an invalid 00579 extension, and if "s" exists, could errantly 00580 cause execution of extensions you don't expect It 00581 makes more sense to let nature take its course 00582 when chan finishes, and let the pbx do its thing 00583 and hang up when the park is over. 00584 */ 00585 if (chan->_state != AST_STATE_UP) 00586 res = ast_answer(chan); 00587 if (!res) 00588 res = ast_safe_sleep(chan, 1000); 00589 00590 if (!res) { /* one direction used to call park_call.... */ 00591 masq_park_call_announce(parkee, parker, 0, NULL, orig_chan_name); 00592 res = 0; /* PBX should hangup zombie channel */ 00593 } 00594 00595 ast_module_user_remove(u); 00596 return res; 00597 00598 }
static int check_compat | ( | struct ast_channel * | c, | |
struct ast_channel * | newchan | |||
) | [static] |
Definition at line 804 of file res_features.c.
References ast_channel_make_compatible(), ast_hangup(), ast_log(), LOG_WARNING, and ast_channel::name.
Referenced by do_atxfer().
00805 { 00806 if (ast_channel_make_compatible(c, newchan) < 0) { 00807 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", 00808 c->name, newchan->name); 00809 ast_hangup(newchan); 00810 return -1; 00811 } 00812 return 0; 00813 }
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, ast_channel::name, 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, "%s", 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 cmd_atxfer | ( | struct ast_channel * | a, | |
struct ast_channel * | b, | |||
struct ast_bridge_config * | conf, | |||
struct ast_channel * | who, | |||
char * | xferto | |||
) | [static] |
Definition at line 1468 of file res_features.c.
References context, do_atxfer(), FEATURE_SENSE_CHAN, and FEATURE_SENSE_PEER.
Referenced by ast_bridge_call().
01469 { 01470 int sense = (a == who) ? FEATURE_SENSE_CHAN : FEATURE_SENSE_PEER; 01471 char *context = strchr(xferto, '@');; 01472 if (context) 01473 *context++ = '\0'; 01474 do_atxfer(a, b, conf, sense, xferto, context); 01475 }
static int do_atxfer | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config, | |||
int | sense, | |||
const char * | toExt, | |||
const char * | toCont | |||
) | [static] |
Attended transfer implementation.
chan | transfered user | |
peer | person transfering call | |
config | ||
sense | feature options | |
toExt | ||
toCont | This is the actual implementation of attended transfer, it can be activated as a regular feature or through the AMI. "toExt" is the extension to transfer to (default: ask for it on the transferer channel) "toCont" is the context to transfer to (default: the one in which the transferer is) |
Definition at line 830 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_datastore_find(), ast_channel_lock, ast_channel_masquerade(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, ast_copy_flags, ast_copy_string(), 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_strlen_zero(), 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_datastore::data, dial_features_info, ast_bridge_config::end_bridge_callback_data_fixup, ast_channel::exten, f, FEATURE_RETURN_SUCCESS, ast_bridge_config::features_callee, ast_dial_features::features_callee, ast_bridge_config::features_caller, finishup(), ast_dial_features::is_caller, ast_channel::language, LOG_DEBUG, LOG_WARNING, ast_channel::name, ast_channel::nativeformats, option_debug, ast_bridge_thread_obj::peer, ast_channel::priority, ast_channel::readformat, real_ctx(), S_OR, set_peers(), ast_channel::visible_indication, and ast_channel::writeformat.
Referenced by builtin_atxfer(), and cmd_atxfer().
00831 { 00832 struct ast_channel *transferer; 00833 struct ast_channel *transferee; 00834 const char *transferer_real_context; 00835 const char *transfer_context; 00836 char xferto[256] = ""; 00837 int res; 00838 int outstate=0; 00839 struct ast_channel *newchan; 00840 struct ast_channel *xferchan; 00841 struct ast_bridge_thread_obj *tobj; 00842 struct ast_bridge_config bconfig; 00843 struct ast_frame *f; 00844 int l; 00845 struct ast_datastore *features_datastore; 00846 struct ast_dial_features *dialfeatures = NULL; 00847 00848 if (option_debug) 00849 ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense); 00850 set_peers(&transferer, &transferee, peer, chan, sense); 00851 transferer_real_context = real_ctx(transferer, transferee); 00852 transfer_context = S_OR(toCont, transferer_real_context); 00853 00854 /* Start autoservice on chan while we talk to the originator */ 00855 ast_autoservice_start(transferee); 00856 ast_indicate(transferee, AST_CONTROL_HOLD); 00857 00858 if (!ast_strlen_zero(toExt)) { 00859 ast_copy_string(xferto, toExt, sizeof(xferto)); 00860 } else { 00861 /* Ask for extension to transfer to on the transferer channel */ 00862 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY); 00863 if (res < 0) { 00864 finishup(transferee); 00865 return res; 00866 } 00867 if (res > 0) /* If they've typed a digit already, handle it */ 00868 xferto[0] = (char) res; 00869 00870 /* this is specific of atxfer */ 00871 res = ast_app_dtget(transferer, transfer_context, xferto, sizeof(xferto), 100, transferdigittimeout); 00872 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */ 00873 finishup(transferee); 00874 return res; 00875 } 00876 if (res == 0) { 00877 ast_log(LOG_WARNING, "Did not read data.\n"); 00878 finishup(transferee); 00879 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, "")) 00880 return -1; 00881 return FEATURE_RETURN_SUCCESS; 00882 } 00883 } 00884 00885 /* valid extension, res == 1 */ 00886 if (!ast_exists_extension(transferer, transfer_context, xferto, 1, transferer->cid.cid_num)) { 00887 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transfer_context); 00888 finishup(transferee); 00889 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, "")) 00890 return -1; 00891 return FEATURE_RETURN_SUCCESS; 00892 } 00893 00894 l = strlen(xferto); 00895 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transfer_context); /* append context */ 00896 newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats), 00897 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, transferer->language); 00898 00899 /* If we are the callee and we are being transferred, after the masquerade 00900 * caller features will really be the original callee features */ 00901 ast_channel_lock(transferee); 00902 if ((features_datastore = ast_channel_datastore_find(transferee, &dial_features_info, NULL))) { 00903 dialfeatures = features_datastore->data; 00904 } 00905 ast_channel_unlock(transferee); 00906 00907 if (dialfeatures && !dialfeatures->is_caller) { 00908 ast_copy_flags(&(config->features_caller), &(dialfeatures->features_callee), AST_FLAGS_ALL); 00909 } 00910 00911 ast_indicate(transferer, -1); 00912 if (!newchan) { 00913 finishup(transferee); 00914 /* any reason besides user requested cancel and busy triggers the failed sound */ 00915 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY && 00916 ast_stream_and_wait(transferer, xferfailsound, transferer->language, "")) 00917 return -1; 00918 return FEATURE_RETURN_SUCCESS; 00919 } 00920 00921 if (check_compat(transferer, newchan)) { 00922 /* we do mean transferee here, NOT transferer */ 00923 finishup(transferee); 00924 return -1; 00925 } 00926 memset(&bconfig,0,sizeof(struct ast_bridge_config)); 00927 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 00928 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 00929 res = ast_bridge_call(transferer, newchan, &bconfig); 00930 if (newchan->_softhangup || !transferer->_softhangup) { 00931 ast_hangup(newchan); 00932 if (ast_stream_and_wait(transferer, xfersound, transferer->language, "")) 00933 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 00934 finishup(transferee); 00935 transferer->_softhangup = 0; 00936 return FEATURE_RETURN_SUCCESS; 00937 } 00938 00939 if (check_compat(transferee, newchan)) { 00940 finishup(transferee); 00941 return -1; 00942 } 00943 00944 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00945 00946 if ((ast_autoservice_stop(transferee) < 0) 00947 || (ast_waitfordigit(transferee, 100) < 0) 00948 || (ast_waitfordigit(newchan, 100) < 0) 00949 || ast_check_hangup(transferee) 00950 || ast_check_hangup(newchan)) { 00951 ast_hangup(newchan); 00952 return -1; 00953 } 00954 00955 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name); 00956 if (!xferchan) { 00957 ast_hangup(newchan); 00958 return -1; 00959 } 00960 /* Make formats okay */ 00961 xferchan->visible_indication = transferer->visible_indication; 00962 xferchan->readformat = transferee->readformat; 00963 xferchan->writeformat = transferee->writeformat; 00964 ast_channel_masquerade(xferchan, transferee); 00965 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority); 00966 xferchan->_state = AST_STATE_UP; 00967 ast_clear_flag(xferchan, AST_FLAGS_ALL); 00968 xferchan->_softhangup = 0; 00969 00970 if ((f = ast_read(xferchan))) 00971 ast_frfree(f); 00972 00973 newchan->_state = AST_STATE_UP; 00974 ast_clear_flag(newchan, AST_FLAGS_ALL); 00975 newchan->_softhangup = 0; 00976 00977 tobj = ast_calloc(1, sizeof(struct ast_bridge_thread_obj)); 00978 if (!tobj) { 00979 ast_hangup(xferchan); 00980 ast_hangup(newchan); 00981 return -1; 00982 } 00983 00984 /* For the case where the transfer target is being connected with the original 00985 caller store the target's original features, and apply to the bridge */ 00986 ast_channel_lock(newchan); 00987 if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) { 00988 dialfeatures = features_datastore->data; 00989 } 00990 ast_channel_unlock(newchan); 00991 00992 if (dialfeatures) { 00993 ast_copy_flags(&(config->features_callee), &(dialfeatures->features_callee), AST_FLAGS_ALL); 00994 } 00995 00996 tobj->chan = newchan; 00997 tobj->peer = xferchan; 00998 tobj->bconfig = *config; 00999 01000 if (tobj->bconfig.end_bridge_callback_data_fixup) { 01001 tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan); 01002 } 01003 01004 if (ast_stream_and_wait(newchan, xfersound, newchan->language, "")) 01005 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 01006 ast_bridge_call_thread_launch(tobj); 01007 return -1; /* XXX meaning the channel is bridged ? */ 01008 }
static void* do_parking_thread | ( | void * | ignore | ) | [static] |
Take care of parked calls and unpark them if needed.
Definition at line 1931 of file res_features.c.
References ast_add_extension2(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, 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_samp2tv(), ast_select(), ast_set_flag, ast_strdupa, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verbose(), parkeduser::chan, ast_channel::context, parkeduser::context, ast_datastore::data, dial_features_info, ast_channel::exten, parkeduser::exten, f, ast_channel::fds, free, LOG_DEBUG, LOG_ERROR, LOG_WARNING, parkeduser::moh_trys, ast_channel::name, parkeduser::next, notify_metermaids(), parkeduser::notquiteyet, option_debug, option_verbose, ast_dial_features::options, parking_lock, 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().
01932 { 01933 fd_set rfds, efds; /* results from previous select, to be preserved across loops. */ 01934 FD_ZERO(&rfds); 01935 FD_ZERO(&efds); 01936 01937 for (;;) { 01938 struct parkeduser *pu, *pl, *pt = NULL; 01939 int ms = -1; /* select timeout, uninitialized */ 01940 int max = -1; /* max fd, none there yet */ 01941 fd_set nrfds, nefds; /* args for the next select */ 01942 FD_ZERO(&nrfds); 01943 FD_ZERO(&nefds); 01944 01945 ast_mutex_lock(&parking_lock); 01946 pl = NULL; 01947 pu = parkinglot; 01948 /* navigate the list with prev-cur pointers to support removals */ 01949 while (pu) { 01950 struct ast_channel *chan = pu->chan; /* shorthand */ 01951 int tms; /* timeout for this item */ 01952 int x; /* fd index in channel */ 01953 struct ast_context *con; 01954 01955 if (pu->notquiteyet) { /* Pretend this one isn't here yet */ 01956 pl = pu; 01957 pu = pu->next; 01958 continue; 01959 } 01960 tms = ast_tvdiff_ms(ast_tvnow(), pu->start); 01961 if (tms > pu->parkingtime) { 01962 ast_indicate(chan, AST_CONTROL_UNHOLD); 01963 /* Get chan, exten from derived kludge */ 01964 if (pu->peername[0]) { 01965 char *peername = ast_strdupa(pu->peername); 01966 char *cp = strrchr(peername, '-'); 01967 if (cp) 01968 *cp = 0; 01969 con = ast_context_find(parking_con_dial); 01970 if (!con) { 01971 con = ast_context_create(NULL, parking_con_dial, registrar); 01972 if (!con) 01973 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial); 01974 } 01975 if (con) { 01976 char returnexten[AST_MAX_EXTENSION]; 01977 struct ast_datastore *features_datastore; 01978 struct ast_dial_features *dialfeatures = NULL; 01979 01980 ast_channel_lock(chan); 01981 01982 if ((features_datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL))) 01983 dialfeatures = features_datastore->data; 01984 01985 ast_channel_unlock(chan); 01986 01987 if (!strncmp(peername, "Parked/", 7)) { 01988 peername += 7; 01989 } 01990 01991 if (dialfeatures) 01992 snprintf(returnexten, sizeof(returnexten), "%s|30|%s", peername, dialfeatures->options); 01993 else /* Existing default */ 01994 snprintf(returnexten, sizeof(returnexten), "%s|30|t", peername); 01995 01996 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar); 01997 } 01998 set_c_e_p(chan, parking_con_dial, peername, 1); 01999 } else { 02000 /* They've been waiting too long, send them back to where they came. Theoretically they 02001 should have their original extensions and such, but we copy to be on the safe side */ 02002 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 02003 } 02004 02005 post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan); 02006 02007 if (option_verbose > 1) 02008 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); 02009 /* Start up the PBX, or hang them up */ 02010 if (ast_pbx_start(chan)) { 02011 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name); 02012 ast_hangup(chan); 02013 } 02014 /* And take them out of the parking lot */ 02015 if (pl) 02016 pl->next = pu->next; 02017 else 02018 parkinglot = pu->next; 02019 pt = pu; 02020 pu = pu->next; 02021 con = ast_context_find(parking_con); 02022 if (con) { 02023 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL)) 02024 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 02025 else 02026 notify_metermaids(pt->parkingexten, parking_con); 02027 } else 02028 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 02029 free(pt); 02030 } else { /* still within parking time, process descriptors */ 02031 for (x = 0; x < AST_MAX_FDS; x++) { 02032 struct ast_frame *f; 02033 02034 if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds))) 02035 continue; /* nothing on this descriptor */ 02036 02037 if (FD_ISSET(chan->fds[x], &efds)) 02038 ast_set_flag(chan, AST_FLAG_EXCEPTION); 02039 else 02040 ast_clear_flag(chan, AST_FLAG_EXCEPTION); 02041 chan->fdno = x; 02042 02043 /* See if they need servicing */ 02044 f = ast_read(chan); 02045 if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP)) { 02046 if (f) 02047 ast_frfree(f); 02048 post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan); 02049 02050 /* There's a problem, hang them up*/ 02051 if (option_verbose > 1) 02052 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name); 02053 ast_hangup(chan); 02054 /* And take them out of the parking lot */ 02055 if (pl) 02056 pl->next = pu->next; 02057 else 02058 parkinglot = pu->next; 02059 pt = pu; 02060 pu = pu->next; 02061 con = ast_context_find(parking_con); 02062 if (con) { 02063 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL)) 02064 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 02065 else { 02066 notify_metermaids(pt->parkingexten, parking_con); 02067 } 02068 } else 02069 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 02070 free(pt); 02071 break; 02072 } else { 02073 /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ 02074 ast_frfree(f); 02075 if (pu->moh_trys < 3 && !chan->generatordata) { 02076 if (option_debug) 02077 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n"); 02078 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 02079 S_OR(parkmohclass, NULL), 02080 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 02081 pu->moh_trys++; 02082 } 02083 goto std; /*! \todo XXX Ick: jumping into an else statement??? XXX */ 02084 } 02085 02086 } /* end for */ 02087 if (x >= AST_MAX_FDS) { 02088 std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */ 02089 if (chan->fds[x] > -1) { 02090 FD_SET(chan->fds[x], &nrfds); 02091 FD_SET(chan->fds[x], &nefds); 02092 if (chan->fds[x] > max) 02093 max = chan->fds[x]; 02094 } 02095 } 02096 /* Keep track of our shortest wait */ 02097 if (tms < ms || ms < 0) 02098 ms = tms; 02099 pl = pu; 02100 pu = pu->next; 02101 } 02102 } 02103 } /* end while */ 02104 ast_mutex_unlock(&parking_lock); 02105 rfds = nrfds; 02106 efds = nefds; 02107 { 02108 struct timeval tv = ast_samp2tv(ms, 1000); 02109 /* Wait for something to happen */ 02110 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL); 02111 } 02112 pthread_testcancel(); 02113 } 02114 return NULL; /* Never reached */ 02115 }
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 1103 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_strlen_zero(), ast_test_flag, FEATURE_RETURN_KEEPTRYING, FEATURE_RETURN_SUCCESS, FEATURE_RETURN_SUCCESSBREAK, FEATURE_SENSE_CHAN, LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, pbx_exec(), and pbx_findapp().
01104 { 01105 struct ast_app *app; 01106 struct ast_call_feature *feature = data; 01107 struct ast_channel *work, *idle; 01108 int res; 01109 01110 if (!feature) { /* shouldn't ever happen! */ 01111 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n"); 01112 return -1; 01113 } 01114 01115 if (sense == FEATURE_SENSE_CHAN) { 01116 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 01117 return FEATURE_RETURN_KEEPTRYING; 01118 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 01119 work = chan; 01120 idle = peer; 01121 } else { 01122 work = peer; 01123 idle = chan; 01124 } 01125 } else { 01126 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 01127 return FEATURE_RETURN_KEEPTRYING; 01128 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 01129 work = peer; 01130 idle = chan; 01131 } else { 01132 work = chan; 01133 idle = peer; 01134 } 01135 } 01136 01137 if (!(app = pbx_findapp(feature->app))) { 01138 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app); 01139 return -2; 01140 } 01141 01142 ast_autoservice_start(idle); 01143 01144 if (!ast_strlen_zero(feature->moh_class)) 01145 ast_moh_start(idle, feature->moh_class, NULL); 01146 01147 res = pbx_exec(work, app, feature->app_args); 01148 01149 if (!ast_strlen_zero(feature->moh_class)) 01150 ast_moh_stop(idle); 01151 01152 ast_autoservice_stop(idle); 01153 01154 if (res) 01155 return FEATURE_RETURN_SUCCESSBREAK; 01156 01157 return FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */ 01158 }
static struct ast_call_feature* find_dynamic_feature | ( | const char * | name | ) | [static] |
find a feature by name
Definition at line 1089 of file res_features.c.
References AST_RWLIST_TRAVERSE, ast_call_feature::feature_entry, and ast_call_feature::sname.
Referenced by ast_feature_interpret(), and set_config_flags().
01090 { 01091 struct ast_call_feature *tmp; 01092 01093 AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) { 01094 if (!strcasecmp(tmp->sname, name)) { 01095 break; 01096 } 01097 } 01098 01099 return tmp; 01100 }
static int finishup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 691 of file res_features.c.
References ast_autoservice_stop(), AST_CONTROL_UNHOLD, and ast_indicate().
Referenced by builtin_blindtransfer(), and do_atxfer().
00692 { 00693 ast_indicate(chan, AST_CONTROL_UNHOLD); 00694 00695 return ast_autoservice_stop(chan); 00696 }
static int handle_parkedcalls | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 2348 of file res_features.c.
References ast_cli(), ast_mutex_lock(), ast_mutex_unlock(), parkeduser::chan, parkeduser::context, parkeduser::exten, ast_channel::name, parkeduser::next, parking_lock, parkeduser::parkingexten, parkinglot, parkeduser::parkingtime, parkeduser::priority, RESULT_SUCCESS, and parkeduser::start.
02349 { 02350 struct parkeduser *cur; 02351 int numparked = 0; 02352 02353 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel" 02354 , "Context", "Extension", "Pri", "Timeout"); 02355 02356 ast_mutex_lock(&parking_lock); 02357 02358 for (cur = parkinglot; cur; cur = cur->next) { 02359 ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n" 02360 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten 02361 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)); 02362 02363 numparked++; 02364 } 02365 ast_mutex_unlock(&parking_lock); 02366 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : ""); 02367 02368 02369 return RESULT_SUCCESS; 02370 }
static int handle_showfeatures | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 2306 of file res_features.c.
References ast_cli(), ast_pickup_ext(), AST_RWLIST_EMPTY, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_rwlock_rdlock(), ast_rwlock_unlock(), builtin_features, ast_call_feature::default_exten, ast_call_feature::exten, exten, ast_call_feature::feature_entry, FEATURES_COUNT, features_lock, ast_call_feature::fname, format, parking_con, parking_ext, parking_start, parking_stop, RESULT_SUCCESS, and ast_call_feature::sname.
02307 { 02308 int i; 02309 struct ast_call_feature *feature; 02310 char format[] = "%-25s %-7s %-7s\n"; 02311 02312 ast_cli(fd, format, "Builtin Feature", "Default", "Current"); 02313 ast_cli(fd, format, "---------------", "-------", "-------"); 02314 02315 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */ 02316 02317 ast_rwlock_rdlock(&features_lock); 02318 for (i = 0; i < FEATURES_COUNT; i++) 02319 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten); 02320 ast_rwlock_unlock(&features_lock); 02321 02322 ast_cli(fd, "\n"); 02323 ast_cli(fd, format, "Dynamic Feature", "Default", "Current"); 02324 ast_cli(fd, format, "---------------", "-------", "-------"); 02325 if (AST_RWLIST_EMPTY(&feature_list)) { 02326 ast_cli(fd, "(none)\n"); 02327 } else { 02328 AST_RWLIST_RDLOCK(&feature_list); 02329 AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) { 02330 ast_cli(fd, format, feature->sname, "no def", feature->exten); 02331 } 02332 AST_RWLIST_UNLOCK(&feature_list); 02333 } 02334 ast_cli(fd, "\nCall parking\n"); 02335 ast_cli(fd, "------------\n"); 02336 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext); 02337 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con); 02338 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop); 02339 ast_cli(fd,"\n"); 02340 02341 return RESULT_SUCCESS; 02342 }
static int load_config | ( | void | ) | [static] |
Definition at line 2544 of file res_features.c.
References adsipark, ast_config_load(), ast_copy_string(), AST_FEATURE_FLAG_BYBOTH, 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, parkedcalltransfers, parkfindnext, parking_con, parking_con_dial, parking_ext, parking_start, parking_stop, parkmohclass, pickup_ext, transferdigittimeout, var, xferfailsound, and xfersound.
02545 { 02546 int start = 0, end = 0; 02547 int res; 02548 struct ast_context *con = NULL; 02549 struct ast_config *cfg = NULL; 02550 struct ast_variable *var = NULL; 02551 char old_parking_ext[AST_MAX_EXTENSION]; 02552 char old_parking_con[AST_MAX_EXTENSION] = ""; 02553 02554 if (!ast_strlen_zero(parking_con)) { 02555 strcpy(old_parking_ext, parking_ext); 02556 strcpy(old_parking_con, parking_con); 02557 } 02558 02559 /* Reset to defaults */ 02560 strcpy(parking_con, "parkedcalls"); 02561 strcpy(parking_con_dial, "park-dial"); 02562 strcpy(parking_ext, "700"); 02563 strcpy(pickup_ext, "*8"); 02564 strcpy(parkmohclass, "default"); 02565 courtesytone[0] = '\0'; 02566 strcpy(xfersound, "beep"); 02567 strcpy(xferfailsound, "pbx-invalid"); 02568 parking_start = 701; 02569 parking_stop = 750; 02570 parkfindnext = 0; 02571 adsipark = 0; 02572 parkaddhints = 0; 02573 parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH; 02574 02575 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 02576 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 02577 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 02578 02579 cfg = ast_config_load("features.conf"); 02580 if (!cfg) { 02581 ast_log(LOG_WARNING,"Could not load features.conf\n"); 02582 return AST_MODULE_LOAD_DECLINE; 02583 } 02584 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { 02585 if (!strcasecmp(var->name, "parkext")) { 02586 ast_copy_string(parking_ext, var->value, sizeof(parking_ext)); 02587 } else if (!strcasecmp(var->name, "context")) { 02588 ast_copy_string(parking_con, var->value, sizeof(parking_con)); 02589 } else if (!strcasecmp(var->name, "parkingtime")) { 02590 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) { 02591 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value); 02592 parkingtime = DEFAULT_PARK_TIME; 02593 } else 02594 parkingtime = parkingtime * 1000; 02595 } else if (!strcasecmp(var->name, "parkpos")) { 02596 if (sscanf(var->value, "%d-%d", &start, &end) != 2) { 02597 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); 02598 } else { 02599 parking_start = start; 02600 parking_stop = end; 02601 } 02602 } else if (!strcasecmp(var->name, "findslot")) { 02603 parkfindnext = (!strcasecmp(var->value, "next")); 02604 } else if (!strcasecmp(var->name, "parkinghints")) { 02605 parkaddhints = ast_true(var->value); 02606 } else if (!strcasecmp(var->name, "parkedcalltransfers")) { 02607 if (!strcasecmp(var->value, "no")) 02608 parkedcalltransfers = 0; 02609 else if (!strcasecmp(var->value, "caller")) 02610 parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER; 02611 else if (!strcasecmp(var->value, "callee")) 02612 parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE; 02613 else if (!strcasecmp(var->value, "both")) 02614 parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH; 02615 } else if (!strcasecmp(var->name, "adsipark")) { 02616 adsipark = ast_true(var->value); 02617 } else if (!strcasecmp(var->name, "transferdigittimeout")) { 02618 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) { 02619 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value); 02620 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 02621 } else 02622 transferdigittimeout = transferdigittimeout * 1000; 02623 } else if (!strcasecmp(var->name, "featuredigittimeout")) { 02624 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) { 02625 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value); 02626 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 02627 } 02628 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) { 02629 if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) { 02630 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value); 02631 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 02632 } else 02633 atxfernoanswertimeout = atxfernoanswertimeout * 1000; 02634 } else if (!strcasecmp(var->name, "courtesytone")) { 02635 ast_copy_string(courtesytone, var->value, sizeof(courtesytone)); 02636 } else if (!strcasecmp(var->name, "parkedplay")) { 02637 if (!strcasecmp(var->value, "both")) 02638 parkedplay = 2; 02639 else if (!strcasecmp(var->value, "parked")) 02640 parkedplay = 1; 02641 else 02642 parkedplay = 0; 02643 } else if (!strcasecmp(var->name, "xfersound")) { 02644 ast_copy_string(xfersound, var->value, sizeof(xfersound)); 02645 } else if (!strcasecmp(var->name, "xferfailsound")) { 02646 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound)); 02647 } else if (!strcasecmp(var->name, "pickupexten")) { 02648 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext)); 02649 } else if (!strcasecmp(var->name, "parkedmusicclass")) { 02650 ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass)); 02651 } 02652 } 02653 02654 unmap_features(); 02655 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) { 02656 if (remap_feature(var->name, var->value)) 02657 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); 02658 } 02659 02660 /* Map a key combination to an application*/ 02661 ast_unregister_features(); 02662 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) { 02663 char *tmp_val = ast_strdupa(var->value); 02664 char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 02665 struct ast_call_feature *feature; 02666 02667 /* strsep() sets the argument to NULL if match not found, and it 02668 * is safe to use it with a NULL argument, so we don't check 02669 * between calls. 02670 */ 02671 exten = strsep(&tmp_val,","); 02672 activatedby = strsep(&tmp_val,","); 02673 app = strsep(&tmp_val,","); 02674 app_args = strsep(&tmp_val,","); 02675 moh_class = strsep(&tmp_val,","); 02676 02677 activateon = strsep(&activatedby, "/"); 02678 02679 /*! \todo XXX var_name or app_args ? */ 02680 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) { 02681 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n", 02682 app, exten, activateon, var->name); 02683 continue; 02684 } 02685 02686 AST_RWLIST_RDLOCK(&feature_list); 02687 if ((feature = find_dynamic_feature(var->name))) { 02688 AST_RWLIST_UNLOCK(&feature_list); 02689 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name); 02690 continue; 02691 } 02692 AST_RWLIST_UNLOCK(&feature_list); 02693 02694 if (!(feature = ast_calloc(1, sizeof(*feature)))) 02695 continue; 02696 02697 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN); 02698 ast_copy_string(feature->app, app, FEATURE_APP_LEN); 02699 ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN); 02700 02701 if (app_args) 02702 ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN); 02703 02704 if (moh_class) 02705 ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN); 02706 02707 ast_copy_string(feature->exten, exten, sizeof(feature->exten)); 02708 feature->operation = feature_exec_app; 02709 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF); 02710 02711 /* Allow caller and calle to be specified for backwards compatability */ 02712 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) 02713 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF); 02714 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) 02715 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER); 02716 else { 02717 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s'," 02718 " must be 'self', or 'peer'\n", var->name); 02719 continue; 02720 } 02721 02722 if (ast_strlen_zero(activatedby)) 02723 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 02724 else if (!strcasecmp(activatedby, "caller")) 02725 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER); 02726 else if (!strcasecmp(activatedby, "callee")) 02727 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE); 02728 else if (!strcasecmp(activatedby, "both")) 02729 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 02730 else { 02731 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s'," 02732 " must be 'caller', or 'callee', or 'both'\n", var->name); 02733 continue; 02734 } 02735 02736 ast_register_feature(feature); 02737 02738 if (option_verbose >= 1) 02739 ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten); 02740 } 02741 ast_config_destroy(cfg); 02742 02743 /* Remove the old parking extension */ 02744 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) { 02745 if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar)) 02746 notify_metermaids(old_parking_ext, old_parking_con); 02747 if (option_debug) 02748 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con); 02749 } 02750 02751 if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) { 02752 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); 02753 return -1; 02754 } 02755 res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar); 02756 if (parkaddhints) 02757 park_add_hints(parking_con, parking_start, parking_stop); 02758 if (!res) 02759 notify_metermaids(ast_parking_ext(), parking_con); 02760 return res; 02761 02762 }
static int load_module | ( | void | ) | [static] |
Definition at line 2769 of file res_features.c.
References ast_cli_register_multiple(), ast_devstate_prov_add(), ast_manager_register, ast_manager_register2(), ast_pthread_create, ast_register_application(), cli_features, descrip, descrip2, do_parking_thread(), EVENT_FLAG_CALL, load_config(), manager_park(), manager_parking_status(), mandescr_park, metermaidstate(), park_call_exec(), park_exec(), parkcall, parkedcall, parking_con, parking_ext, parking_thread, synopsis, and synopsis2.
02770 { 02771 int res; 02772 02773 memset(parking_ext, 0, sizeof(parking_ext)); 02774 memset(parking_con, 0, sizeof(parking_con)); 02775 02776 if ((res = load_config())) 02777 return res; 02778 ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); 02779 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL); 02780 res = ast_register_application(parkedcall, park_exec, synopsis, descrip); 02781 if (!res) 02782 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2); 02783 if (!res) { 02784 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" ); 02785 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park, 02786 "Park a channel", mandescr_park); 02787 } 02788 02789 res |= ast_devstate_prov_add("Park", metermaidstate); 02790 02791 return res; 02792 }
static int manager_park | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 2439 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(), and s.
Referenced by load_module().
02440 { 02441 const char *channel = astman_get_header(m, "Channel"); 02442 const char *channel2 = astman_get_header(m, "Channel2"); 02443 const char *timeout = astman_get_header(m, "Timeout"); 02444 char buf[BUFSIZ]; 02445 int to = 0; 02446 int res = 0; 02447 int parkExt = 0; 02448 struct ast_channel *ch1, *ch2; 02449 02450 if (ast_strlen_zero(channel)) { 02451 astman_send_error(s, m, "Channel not specified"); 02452 return 0; 02453 } 02454 02455 if (ast_strlen_zero(channel2)) { 02456 astman_send_error(s, m, "Channel2 not specified"); 02457 return 0; 02458 } 02459 02460 ch1 = ast_get_channel_by_name_locked(channel); 02461 if (!ch1) { 02462 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel); 02463 astman_send_error(s, m, buf); 02464 return 0; 02465 } 02466 02467 ch2 = ast_get_channel_by_name_locked(channel2); 02468 if (!ch2) { 02469 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2); 02470 astman_send_error(s, m, buf); 02471 ast_channel_unlock(ch1); 02472 return 0; 02473 } 02474 02475 if (!ast_strlen_zero(timeout)) { 02476 sscanf(timeout, "%d", &to); 02477 } 02478 02479 res = ast_masq_park_call(ch1, ch2, to, &parkExt); 02480 if (!res) { 02481 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT); 02482 astman_send_ack(s, m, "Park successful"); 02483 } else { 02484 astman_send_error(s, m, "Park failure"); 02485 } 02486 02487 ast_channel_unlock(ch1); 02488 ast_channel_unlock(ch2); 02489 02490 return 0; 02491 }
static int manager_parking_status | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Dump lot status.
Definition at line 2392 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, ast_channel::name, parkeduser::next, parking_lock, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, RESULT_SUCCESS, s, S_OR, and parkeduser::start.
Referenced by load_module().
02393 { 02394 struct parkeduser *cur; 02395 const char *id = astman_get_header(m, "ActionID"); 02396 char idText[256] = ""; 02397 02398 if (!ast_strlen_zero(id)) 02399 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 02400 02401 astman_send_ack(s, m, "Parked calls will follow"); 02402 02403 ast_mutex_lock(&parking_lock); 02404 02405 for (cur = parkinglot; cur; cur = cur->next) { 02406 astman_append(s, "Event: ParkedCall\r\n" 02407 "Exten: %d\r\n" 02408 "Channel: %s\r\n" 02409 "From: %s\r\n" 02410 "Timeout: %ld\r\n" 02411 "CallerID: %s\r\n" 02412 "CallerIDName: %s\r\n" 02413 "%s" 02414 "\r\n", 02415 cur->parkingnum, cur->chan->name, cur->peername, 02416 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL), 02417 S_OR(cur->chan->cid.cid_num, ""), /* XXX in other places it is <unknown> */ 02418 S_OR(cur->chan->cid.cid_name, ""), 02419 idText); 02420 } 02421 02422 astman_append(s, 02423 "Event: ParkedCallsComplete\r\n" 02424 "%s" 02425 "\r\n",idText); 02426 02427 ast_mutex_unlock(&parking_lock); 02428 02429 return RESULT_SUCCESS; 02430 }
static int masq_park_call | ( | struct ast_channel * | rchan, | |
struct ast_channel * | peer, | |||
int | timeout, | |||
int * | extout, | |||
int | play_announcement, | |||
const char * | orig_chan_name | |||
) | [static] |
Definition at line 487 of file res_features.c.
References ast_channel::accountcode, ast_channel::amaflags, ast_channel_alloc(), ast_channel_masquerade(), ast_frfree, ast_hangup(), ast_log(), ast_read(), AST_STATE_DOWN, ast_strdupa, ast_channel::context, ast_channel::exten, f, LOG_WARNING, ast_channel::name, park_call_full(), ast_channel::priority, ast_channel::readformat, set_c_e_p(), and ast_channel::writeformat.
Referenced by ast_masq_park_call(), and masq_park_call_announce().
00488 { 00489 struct ast_channel *chan; 00490 struct ast_frame *f; 00491 int park_status; 00492 00493 /* Make a new, fake channel that we'll use to masquerade in the real one */ 00494 if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) { 00495 ast_log(LOG_WARNING, "Unable to create parked channel\n"); 00496 return -1; 00497 } 00498 00499 /* Make formats okay */ 00500 chan->readformat = rchan->readformat; 00501 chan->writeformat = rchan->writeformat; 00502 ast_channel_masquerade(chan, rchan); 00503 00504 /* Setup the extensions and such */ 00505 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority); 00506 00507 /* Make the masq execute */ 00508 if ((f = ast_read(chan))) { 00509 ast_frfree(f); 00510 } 00511 00512 if (peer == rchan) { 00513 peer = chan; 00514 } 00515 00516 if (!play_announcement || !orig_chan_name) { 00517 orig_chan_name = ast_strdupa(chan->name); 00518 } 00519 00520 park_status = park_call_full(chan, peer, timeout, extout, orig_chan_name); 00521 if (park_status == 1) { 00522 /* would be nice to play: "invalid parking extension" */ 00523 ast_hangup(chan); 00524 return -1; 00525 } 00526 00527 return 0; 00528 }
static int masq_park_call_announce | ( | struct ast_channel * | rchan, | |
struct ast_channel * | peer, | |||
int | timeout, | |||
int * | extout, | |||
const char * | orig_chan_name | |||
) | [static] |
Definition at line 535 of file res_features.c.
References masq_park_call().
Referenced by builtin_blindtransfer(), builtin_parkcall(), and park_call_exec().
00536 { 00537 return masq_park_call(rchan, peer, timeout, extout, 1, orig_chan_name); 00538 }
static int metermaidstate | ( | const char * | data | ) | [static] |
metermaids callback from devicestate.c
Definition at line 284 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, and option_debug.
Referenced by load_module().
00285 { 00286 int res = AST_DEVICE_INVALID; 00287 char *context = ast_strdupa(data); 00288 char *exten; 00289 00290 exten = strsep(&context, "@"); 00291 if (!context) 00292 return res; 00293 00294 if (option_debug > 3) 00295 ast_log(LOG_DEBUG, "Checking state of exten %s in context %s\n", exten, context); 00296 00297 res = ast_exists_extension(NULL, context, exten, 1, NULL); 00298 00299 if (!res) 00300 return AST_DEVICE_NOT_INUSE; 00301 else 00302 return AST_DEVICE_INUSE; 00303 }
static void notify_metermaids | ( | char * | exten, | |
char * | context | |||
) | [static] |
Notify metermaids that we've changed an extension.
Definition at line 273 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().
00274 { 00275 if (option_debug > 3) 00276 ast_log(LOG_DEBUG, "Notification of state change to metermaids %s@%s\n", exten, context); 00277 00278 /* Send notification to devicestate subsystem */ 00279 ast_device_state_changed("park:%s@%s", exten, context); 00280 return; 00281 }
static void park_add_hints | ( | char * | context, | |
int | start, | |||
int | stop | |||
) | [static] |
Add parking hints for all defined parking lots.
Definition at line 2530 of file res_features.c.
References ast_add_extension(), AST_MAX_EXTENSION, exten, PRIORITY_HINT, and registrar.
02531 { 02532 int numext; 02533 char device[AST_MAX_EXTENSION]; 02534 char exten[10]; 02535 02536 for (numext = start; numext <= stop; numext++) { 02537 snprintf(exten, sizeof(exten), "%d", numext); 02538 snprintf(device, sizeof(device), "park:%s@%s", exten, context); 02539 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar); 02540 } 02541 }
static int park_call_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Park a call.
Definition at line 2118 of file res_features.c.
References ast_channel::_state, ast_answer(), ast_copy_string(), AST_MAX_EXTENSION, ast_module_user_add, ast_module_user_remove, ast_safe_sleep(), AST_STATE_UP, ast_strdupa, ast_module_user::chan, ast_channel::exten, masq_park_call_announce(), ast_channel::name, orig_exten(), and ast_channel::priority.
Referenced by load_module().
02119 { 02120 /* Cache the original channel name in case we get masqueraded in the middle 02121 * of a park--it is still theoretically possible for a transfer to happen before 02122 * we get here, but it is _really_ unlikely */ 02123 char *orig_chan_name = ast_strdupa(chan->name); 02124 char orig_exten[AST_MAX_EXTENSION]; 02125 int orig_priority = chan->priority; 02126 02127 /* Data is unused at the moment but could contain a parking 02128 lot context eventually */ 02129 int res = 0; 02130 struct ast_module_user *u; 02131 02132 u = ast_module_user_add(chan); 02133 02134 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten)); 02135 02136 /* Setup the exten/priority to be s/1 since we don't know 02137 where this call should return */ 02138 strcpy(chan->exten, "s"); 02139 chan->priority = 1; 02140 /* Answer if call is not up */ 02141 if (chan->_state != AST_STATE_UP) 02142 res = ast_answer(chan); 02143 /* Sleep to allow VoIP streams to settle down */ 02144 if (!res) 02145 res = ast_safe_sleep(chan, 1000); 02146 /* Park the call */ 02147 if (!res) { 02148 res = masq_park_call_announce(chan, chan, 0, NULL, orig_chan_name); 02149 /* Continue on in the dialplan */ 02150 if (res == 1) { 02151 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten)); 02152 chan->priority = orig_priority; 02153 res = 0; 02154 } else if (!res) { 02155 res = 1; 02156 } 02157 } 02158 02159 ast_module_user_remove(u); 02160 02161 return res; 02162 }
static int park_call_full | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
int | timeout, | |||
int * | extout, | |||
const char * | orig_chan_name | |||
) | [static] |
Definition at line 305 of file res_features.c.
References adsi_announce_park(), ast_channel::appl, ast_add_extension2(), ast_adsi_available(), ast_adsi_unload_session(), ast_bridged_channel(), ast_calloc, AST_CHANNEL_NAME, ast_channel_unlock, ast_clear_flag, ast_context_create(), ast_context_find(), AST_CONTROL_HOLD, ast_copy_string(), ast_exists_extension(), AST_FLAG_MASQ_NOSTREAM, ast_free, ast_get_channel_by_name_locked(), ast_indicate_data(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_say_digits(), ast_set_flag, ast_strlen_zero(), ast_tvnow(), 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(), ast_channel::name, parkeduser::next, notify_metermaids(), option_verbose, parking_lock, parkinglot, parkeduser::parkingnum, pbx_builtin_getvar_helper(), ast_channel::priority, S_OR, strdup, ast_channel::tech, ast_channel_tech::type, and VERBOSE_PREFIX_2.
Referenced by ast_park_call(), and masq_park_call().
00306 { 00307 struct parkeduser *pu, *cur; 00308 int i, x = -1, parking_range, parkingnum_copy; 00309 struct ast_context *con; 00310 const char *parkingexten; 00311 00312 /* Allocate memory for parking data */ 00313 if (!(pu = ast_calloc(1, sizeof(*pu)))) 00314 return -1; 00315 00316 /* Lock parking lot */ 00317 ast_mutex_lock(&parking_lock); 00318 /* Check for channel variable PARKINGEXTEN */ 00319 parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN"); 00320 if (!ast_strlen_zero(parkingexten)) { 00321 /*!\note The API forces us to specify a numeric parking slot, even 00322 * though the architecture would tend to support non-numeric extensions 00323 * (as are possible with SIP, for example). Hence, we enforce that 00324 * limitation here. If extout was not numeric, we could permit 00325 * arbitrary non-numeric extensions. 00326 */ 00327 if (sscanf(parkingexten, "%d", &x) != 1 || x < 0) { 00328 ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten); 00329 ast_mutex_unlock(&parking_lock); 00330 free(pu); 00331 return 1; /* Continue execution if possible */ 00332 } 00333 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x); 00334 00335 if (ast_exists_extension(NULL, parking_con, pu->parkingexten, 1, NULL)) { 00336 ast_mutex_unlock(&parking_lock); 00337 free(pu); 00338 ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con); 00339 return 1; /* Continue execution if possible */ 00340 } 00341 } else { 00342 /* Select parking space within range */ 00343 parking_range = parking_stop - parking_start+1; 00344 for (i = 0; i < parking_range; i++) { 00345 x = (i + parking_offset) % parking_range + parking_start; 00346 cur = parkinglot; 00347 while(cur) { 00348 if (cur->parkingnum == x) 00349 break; 00350 cur = cur->next; 00351 } 00352 if (!cur) 00353 break; 00354 } 00355 00356 if (!(i < parking_range)) { 00357 ast_log(LOG_WARNING, "No more parking spaces\n"); 00358 free(pu); 00359 ast_mutex_unlock(&parking_lock); 00360 return -1; 00361 } 00362 /* Set pointer for next parking */ 00363 if (parkfindnext) 00364 parking_offset = x - parking_start + 1; 00365 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x); 00366 } 00367 00368 chan->appl = "Parked Call"; 00369 chan->data = NULL; 00370 00371 pu->chan = chan; 00372 00373 /* Put the parked channel on hold if we have two different channels */ 00374 if (chan != peer) { 00375 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 00376 S_OR(parkmohclass, NULL), 00377 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 00378 } 00379 00380 pu->start = ast_tvnow(); 00381 pu->parkingnum = x; 00382 pu->parkingtime = (timeout > 0) ? timeout : parkingtime; 00383 if (extout) 00384 *extout = x; 00385 00386 if (peer) { 00387 /* This is so ugly that it hurts, but implementing get_base_channel() on local channels 00388 could have ugly side effects. We could have transferer<->local,1<->local,2<->parking 00389 and we need the callback name to be that of transferer. Since local,1/2 have the same 00390 name we can be tricky and just grab the bridged channel from the other side of the local 00391 */ 00392 if (!strcasecmp(peer->tech->type, "Local")) { 00393 struct ast_channel *tmpchan, *base_peer; 00394 char other_side[AST_CHANNEL_NAME]; 00395 char *c; 00396 ast_copy_string(other_side, S_OR(orig_chan_name, peer->name), sizeof(other_side)); 00397 if ((c = strrchr(other_side, ','))) { 00398 *++c = '1'; 00399 } 00400 if ((tmpchan = ast_get_channel_by_name_locked(other_side))) { 00401 if ((base_peer = ast_bridged_channel(tmpchan))) { 00402 ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername)); 00403 } 00404 ast_channel_unlock(tmpchan); 00405 } 00406 } else { 00407 ast_copy_string(pu->peername, S_OR(orig_chan_name, peer->name), sizeof(pu->peername)); 00408 } 00409 } 00410 00411 /* Remember what had been dialed, so that if the parking 00412 expires, we try to come back to the same place */ 00413 ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context)); 00414 ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten)); 00415 pu->priority = chan->macropriority ? chan->macropriority : chan->priority; 00416 pu->next = parkinglot; 00417 parkinglot = pu; 00418 parkingnum_copy = pu->parkingnum; 00419 /* If parking a channel directly, don't quite yet get parking running on it */ 00420 if (peer == chan) 00421 pu->notquiteyet = 1; 00422 00423 if (option_verbose > 1) 00424 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)); 00425 00426 manager_event(EVENT_FLAG_CALL, "ParkedCall", 00427 "Exten: %s\r\n" 00428 "Channel: %s\r\n" 00429 "From: %s\r\n" 00430 "Timeout: %ld\r\n" 00431 "CallerID: %s\r\n" 00432 "CallerIDName: %s\r\n", 00433 pu->parkingexten, pu->chan->name, peer ? peer->name : "", 00434 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL), 00435 S_OR(pu->chan->cid.cid_num, "<unknown>"), 00436 S_OR(pu->chan->cid.cid_name, "<unknown>") 00437 ); 00438 00439 if (peer && adsipark && ast_adsi_available(peer)) { 00440 adsi_announce_park(peer, pu->parkingexten); /* Only supports parking numbers */ 00441 ast_adsi_unload_session(peer); 00442 } 00443 00444 con = ast_context_find(parking_con); 00445 if (!con) 00446 con = ast_context_create(NULL, parking_con, registrar); 00447 if (!con) /* Still no context? Bad */ 00448 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); 00449 if (con) { 00450 if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), ast_free, registrar)) { 00451 notify_metermaids(pu->parkingexten, parking_con); 00452 } 00453 } 00454 00455 ast_mutex_unlock(&parking_lock); 00456 /* Wake up the (presumably select()ing) thread */ 00457 pthread_kill(parking_thread, SIGURG); 00458 00459 /* Only say number if it's a number and the channel hasn't been masqueraded away */ 00460 if (peer && (ast_strlen_zero(orig_chan_name) || !strcasecmp(peer->name, orig_chan_name))) { 00461 /* Make sure we don't start saying digits to the channel being parked */ 00462 ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM); 00463 /* Tell the peer channel the number of the parking space */ 00464 ast_say_digits(peer, parkingnum_copy, "", peer->language); 00465 ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM); 00466 } 00467 00468 if (peer == chan) { /* pu->notquiteyet = 1 */ 00469 /* Wake up parking thread if we're really done */ 00470 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 00471 S_OR(parkmohclass, NULL), 00472 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 00473 pu->notquiteyet = 0; 00474 pthread_kill(parking_thread, SIGURG); 00475 } 00476 return 0; 00477 }
static int park_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Pickup parked call.
Definition at line 2165 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_FLAG_BYBOTH, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_REDIRECT, ast_hangup(), ast_indicate(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_mutex_lock(), ast_mutex_unlock(), 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, EVENT_FLAG_CALL, free, LOG_WARNING, manager_event(), ast_channel::name, parkeduser::next, notify_metermaids(), option_verbose, parkedcalltransfers, parkedplay, parking_con, parking_lock, parkeduser::parkingexten, parkinglot, parkeduser::parkingnum, ast_channel::pbx, pbx_builtin_setvar_helper(), S_OR, and VERBOSE_PREFIX_3.
Referenced by load_module().
02166 { 02167 int res = 0; 02168 struct ast_module_user *u; 02169 struct ast_channel *peer=NULL; 02170 struct parkeduser *pu, *pl=NULL; 02171 struct ast_context *con; 02172 02173 int park; 02174 struct ast_bridge_config config; 02175 02176 if (!data) { 02177 ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n"); 02178 return -1; 02179 } 02180 02181 u = ast_module_user_add(chan); 02182 02183 park = atoi((char *)data); 02184 ast_mutex_lock(&parking_lock); 02185 pu = parkinglot; 02186 while(pu) { 02187 if (pu->parkingnum == park) { 02188 if (pu->chan->pbx) { /* do not allow call to be picked up until the PBX thread is finished */ 02189 ast_mutex_unlock(&parking_lock); 02190 ast_module_user_remove(u); 02191 return -1; 02192 } 02193 if (pl) 02194 pl->next = pu->next; 02195 else 02196 parkinglot = pu->next; 02197 break; 02198 } 02199 pl = pu; 02200 pu = pu->next; 02201 } 02202 ast_mutex_unlock(&parking_lock); 02203 if (pu) { 02204 peer = pu->chan; 02205 con = ast_context_find(parking_con); 02206 if (con) { 02207 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL)) 02208 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 02209 else 02210 notify_metermaids(pu->parkingexten, parking_con); 02211 } else 02212 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 02213 02214 manager_event(EVENT_FLAG_CALL, "UnParkedCall", 02215 "Exten: %s\r\n" 02216 "Channel: %s\r\n" 02217 "From: %s\r\n" 02218 "CallerID: %s\r\n" 02219 "CallerIDName: %s\r\n", 02220 pu->parkingexten, pu->chan->name, chan->name, 02221 S_OR(pu->chan->cid.cid_num, "<unknown>"), 02222 S_OR(pu->chan->cid.cid_name, "<unknown>") 02223 ); 02224 02225 free(pu); 02226 } 02227 /* JK02: it helps to answer the channel if not already up */ 02228 if (chan->_state != AST_STATE_UP) 02229 ast_answer(chan); 02230 02231 if (peer) { 02232 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */ 02233 02234 if (!ast_strlen_zero(courtesytone)) { 02235 int error = 0; 02236 ast_indicate(peer, AST_CONTROL_UNHOLD); 02237 if (parkedplay == 0) { 02238 error = ast_stream_and_wait(chan, courtesytone, chan->language, ""); 02239 } else if (parkedplay == 1) { 02240 error = ast_stream_and_wait(peer, courtesytone, chan->language, ""); 02241 } else if (parkedplay == 2) { 02242 if (!ast_streamfile(chan, courtesytone, chan->language) && 02243 !ast_streamfile(peer, courtesytone, chan->language)) { 02244 /*! \todo XXX we would like to wait on both! */ 02245 res = ast_waitstream(chan, ""); 02246 if (res >= 0) 02247 res = ast_waitstream(peer, ""); 02248 if (res < 0) 02249 error = 1; 02250 } 02251 } 02252 if (error) { 02253 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 02254 ast_hangup(peer); 02255 ast_module_user_remove(u); 02256 return -1; 02257 } 02258 } else 02259 ast_indicate(peer, AST_CONTROL_UNHOLD); 02260 02261 res = ast_channel_make_compatible(chan, peer); 02262 if (res < 0) { 02263 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); 02264 ast_hangup(peer); 02265 ast_module_user_remove(u); 02266 return -1; 02267 } 02268 /* This runs sorta backwards, since we give the incoming channel control, as if it 02269 were the person called. */ 02270 if (option_verbose > 2) 02271 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park); 02272 02273 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 02274 ast_cdr_setdestchan(chan->cdr, peer->name); 02275 memset(&config, 0, sizeof(struct ast_bridge_config)); 02276 02277 if ((parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 02278 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 02279 } 02280 if ((parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 02281 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 02282 } 02283 res = ast_bridge_call(chan, peer, &config); 02284 02285 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 02286 ast_cdr_setdestchan(chan->cdr, peer->name); 02287 02288 /* Simulate the PBX hanging up */ 02289 ast_hangup(peer); 02290 ast_module_user_remove(u); 02291 return res; 02292 } else { 02293 /*! \todo XXX Play a message XXX */ 02294 if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, "")) 02295 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name); 02296 if (option_verbose > 2) 02297 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park); 02298 res = -1; 02299 } 02300 02301 ast_module_user_remove(u); 02302 02303 return res; 02304 }
Definition at line 1456 of file res_features.c.
References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.
Referenced by ast_bridge_call().
01457 { 01458 struct ast_cdr *cdr_orig = cdr; 01459 while (cdr) { 01460 if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED)) 01461 return cdr; 01462 cdr = cdr->next; 01463 } 01464 return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */ 01465 }
static void post_manager_event | ( | const char * | s, | |
char * | parkingexten, | |||
struct ast_channel * | chan | |||
) | [static] |
Definition at line 1916 of file res_features.c.
References ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, EVENT_FLAG_CALL, manager_event(), ast_channel::name, and S_OR.
Referenced by do_parking_thread().
01917 { 01918 manager_event(EVENT_FLAG_CALL, s, 01919 "Exten: %s\r\n" 01920 "Channel: %s\r\n" 01921 "CallerID: %s\r\n" 01922 "CallerIDName: %s\r\n\r\n", 01923 parkingexten, 01924 chan->name, 01925 S_OR(chan->cid.cid_num, "<unknown>"), 01926 S_OR(chan->cid.cid_name, "<unknown>") 01927 ); 01928 }
static const char* real_ctx | ( | struct ast_channel * | transferer, | |
struct ast_channel * | transferee | |||
) | [static] |
Find the context for the transfer.
Definition at line 699 of file res_features.c.
References ast_strlen_zero(), ast_channel::context, ast_channel::macrocontext, pbx_builtin_getvar_helper(), and s.
Referenced by builtin_blindtransfer(), and do_atxfer().
00700 { 00701 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"); 00702 if (ast_strlen_zero(s)) 00703 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT"); 00704 if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */ 00705 s = transferer->macrocontext; 00706 if (ast_strlen_zero(s)) 00707 s = transferer->context; 00708 return s; 00709 }
static int reload | ( | void | ) | [static] |
Definition at line 2764 of file res_features.c.
References load_config().
02765 { 02766 return load_config(); 02767 }
static int remap_feature | ( | const char * | name, | |
const char * | value | |||
) | [static] |
Definition at line 1170 of file res_features.c.
References ast_copy_string(), ast_rwlock_unlock(), ast_rwlock_wrlock(), builtin_features, exten, FEATURES_COUNT, and features_lock.
01171 { 01172 int x, res = -1; 01173 01174 ast_rwlock_wrlock(&features_lock); 01175 for (x = 0; x < FEATURES_COUNT; x++) { 01176 if (strcasecmp(builtin_features[x].sname, name)) 01177 continue; 01178 01179 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten)); 01180 res = 0; 01181 break; 01182 } 01183 ast_rwlock_unlock(&features_lock); 01184 01185 return res; 01186 }
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_copy_string(), ast_channel::context, ast_channel::exten, and ast_channel::priority.
Referenced by builtin_blindtransfer(), do_parking_thread(), and masq_park_call().
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 1256 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_RWLIST_RDLOCK, AST_RWLIST_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, features_lock, find_dynamic_feature(), and pbx_builtin_getvar_helper().
Referenced by ast_bridge_call().
01257 { 01258 int x; 01259 01260 ast_clear_flag(config, AST_FLAGS_ALL); 01261 01262 ast_rwlock_rdlock(&features_lock); 01263 for (x = 0; x < FEATURES_COUNT; x++) { 01264 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) 01265 continue; 01266 01267 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask)) 01268 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 01269 01270 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask)) 01271 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 01272 } 01273 ast_rwlock_unlock(&features_lock); 01274 01275 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) { 01276 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"); 01277 01278 if (dynamic_features) { 01279 char *tmp = ast_strdupa(dynamic_features); 01280 char *tok; 01281 struct ast_call_feature *feature; 01282 01283 /* while we have a feature */ 01284 while ((tok = strsep(&tmp, "#"))) { 01285 AST_RWLIST_RDLOCK(&feature_list); 01286 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) { 01287 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 01288 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 01289 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 01290 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 01291 } 01292 AST_RWLIST_UNLOCK(&feature_list); 01293 } 01294 } 01295 } 01296 }
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 552 of file res_features.c.
References FEATURE_SENSE_PEER.
Referenced by builtin_automonitor(), builtin_blindtransfer(), builtin_parkcall(), and do_atxfer().
00554 { 00555 if (sense == FEATURE_SENSE_PEER) { 00556 *caller = peer; 00557 *callee = chan; 00558 } else { 00559 *callee = peer; 00560 *caller = chan; 00561 } 00562 }
static int unload_module | ( | void | ) | [static] |
Definition at line 2795 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.
02796 { 02797 ast_module_user_hangup_all(); 02798 02799 ast_manager_unregister("ParkedCalls"); 02800 ast_manager_unregister("Park"); 02801 ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); 02802 ast_unregister_application(parkcall); 02803 ast_devstate_prov_del("Park"); 02804 return ast_unregister_application(parkedcall); 02805 }
static void unmap_features | ( | void | ) | [static] |
Definition at line 1160 of file res_features.c.
References ast_rwlock_unlock(), ast_rwlock_wrlock(), builtin_features, exten, FEATURES_COUNT, and features_lock.
01161 { 01162 int x; 01163 01164 ast_rwlock_wrlock(&features_lock); 01165 for (x = 0; x < FEATURES_COUNT; x++) 01166 strcpy(builtin_features[x].exten, builtin_features[x].default_exten); 01167 ast_rwlock_unlock(&features_lock); 01168 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_BUILDSUM, .description = "Call Features Resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "f450f61f60e761b3aa089ebed76ca8a5" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 2811 of file res_features.c.
int adsipark [static] |
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 2811 of file res_features.c.
int atxfernoanswertimeout [static] |
struct ast_call_feature builtin_features[] [static] |
Definition at line 1034 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 2381 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 2376 of file res_features.c.
char courtesytone[256] [static] |
Courtesy tone
Definition at line 97 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 117 of file res_features.c.
char* descrip2 [static] |
Definition at line 127 of file res_features.c.
int featuredigittimeout [static] |
Definition at line 108 of file res_features.c.
ast_rwlock_t features_lock = PTHREAD_RWLOCK_INITIALIZER [static] |
Definition at line 1032 of file res_features.c.
Referenced by ast_feature_interpret(), ast_feature_request_and_dial(), handle_showfeatures(), remap_feature(), set_config_flags(), and unmap_features().
char mandescr_park[] [static] |
struct ast_app* monitor_app = NULL [static] |
Definition at line 138 of file res_features.c.
Referenced by ast_bridge_call(), and builtin_automonitor().
int monitor_ok = 1 [static] |
Definition at line 139 of file res_features.c.
int parkaddhints = 0 [static] |
Add parking hints automatically
Definition at line 85 of file res_features.c.
Referenced by load_config().
char* parkcall = PARK_APP_NAME [static] |
char* parkedcall = "ParkedCall" [static] |
int parkedcalltransfers [static] |
Who can REDIRECT after picking up a parked a call
Definition at line 95 of file res_features.c.
Referenced by load_config(), and park_exec().
int parkedplay = 0 [static] |
Who to play the courtesy tone to
Definition at line 98 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 87 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 88 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 89 of file res_features.c.
Referenced by handle_showfeatures(), load_config(), and load_module().
ast_mutex_t parking_lock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) [static] |
protects all static variables above
Definition at line 158 of file res_features.c.
Referenced by do_parking_thread(), handle_parkedcalls(), manager_parking_status(), park_call_full(), and park_exec().
int parking_offset [static] |
Definition at line 102 of file res_features.c.
int parking_start [static] |
First available extension for parking
Definition at line 92 of file res_features.c.
Referenced by handle_showfeatures(), and load_config().
int parking_stop [static] |
Last available extension for parking
Definition at line 93 of file res_features.c.
Referenced by handle_showfeatures(), and load_config().
pthread_t parking_thread [static] |
struct parkeduser* parkinglot [static] |
Definition at line 156 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 86 of file res_features.c.
char parkmohclass[MAX_MUSICCLASS] [static] |
Music class used for parking
Definition at line 91 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 112 of file res_features.c.
char showfeatures_help[] [static] |
Initial value:
"Usage: feature list\n" " Lists currently configured features.\n"
Definition at line 2344 of file res_features.c.
char showparked_help[] [static] |
Initial value:
"Usage: show parkedcalls\n" " Lists currently parked calls.\n"
Definition at line 2372 of file res_features.c.
char* synopsis = "Answer a parked call" [static] |
Definition at line 115 of file res_features.c.
char* synopsis2 = "Park yourself" [static] |
Definition at line 125 of file res_features.c.
int transferdigittimeout [static] |
char xferfailsound[256] [static] |
Call transfer failure sound
Definition at line 100 of file res_features.c.
Referenced by load_config().
char xfersound[256] [static] |