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