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