#include "asterisk.h"
#include <pthread.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/options.h"
#include "asterisk/causes.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/app.h"
#include "asterisk/say.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/config.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/utils.h"
#include "asterisk/adsi.h"
#include "asterisk/devicestate.h"
#include "asterisk/monitor.h"
Go to the source code of this file.
Data Structures | |
struct | ast_bridge_thread_obj |
struct | parkeduser |
Defines | |
#define | AST_MAX_WATCHERS 256 |
#define | DEFAULT_FEATURE_DIGIT_TIMEOUT 500 |
#define | DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000 |
#define | DEFAULT_PARK_TIME 45000 |
#define | DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 |
#define | FEATURE_RETURN_HANGUP -1 |
#define | FEATURE_RETURN_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. | |
char * | ast_parking_ext (void) |
Determine system parking extension Returns the call parking extension for drivers that provide special call parking help. | |
int | ast_pickup_call (struct ast_channel *chan) |
Pickup a call. | |
char * | ast_pickup_ext (void) |
Determine system call pickup extension. | |
void | ast_register_feature (struct ast_call_feature *feature) |
register new feature into feature_list | |
AST_RWLOCK_DEFINE_STATIC (features_lock) | |
void | ast_unregister_feature (struct ast_call_feature *feature) |
unregister feature from feature_list | |
static void | ast_unregister_features (void) |
Remove all features in the list. | |
static int | 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 |
#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 878 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 1326 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, ast_option_header::data, ast_frame::data, ast_channel::data, ast_frame::datalen, ast_cdr::dstchannel, ast_bridge_config::end_sound, f, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_bridge_config::feature_timer, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_bridge_config::firstpass, ast_option_header::flag, ast_frame::frametype, free, LOG_DEBUG, LOG_WARNING, ast_option_header::option, option_debug, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), ast_bridge_config::play_warning, set_config_flags(), ast_bridge_config::start_sound, ast_bridge_config::start_time, ast_frame::subclass, ast_cdr::userfield, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.
01327 { 01328 /* Copy voice back and forth between the two channels. Give the peer 01329 the ability to transfer calls with '#<extension' syntax. */ 01330 struct ast_frame *f; 01331 struct ast_channel *who; 01332 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 01333 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 01334 int res; 01335 int diff; 01336 int hasfeatures=0; 01337 int hadfeatures=0; 01338 struct ast_option_header *aoh; 01339 struct ast_bridge_config backup_config; 01340 struct ast_cdr *bridge_cdr; 01341 01342 memset(&backup_config, 0, sizeof(backup_config)); 01343 01344 config->start_time = ast_tvnow(); 01345 01346 if (chan && peer) { 01347 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 01348 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 01349 } else if (chan) 01350 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 01351 01352 if (monitor_ok) { 01353 const char *monitor_exec; 01354 struct ast_channel *src = NULL; 01355 if (!monitor_app) { 01356 if (!(monitor_app = pbx_findapp("Monitor"))) 01357 monitor_ok=0; 01358 } 01359 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 01360 src = chan; 01361 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 01362 src = peer; 01363 if (monitor_app && src) { 01364 char *tmp = ast_strdupa(monitor_exec); 01365 pbx_exec(src, monitor_app, tmp); 01366 } 01367 } 01368 01369 set_config_flags(chan, peer, config); 01370 config->firstpass = 1; 01371 01372 /* Answer if need be */ 01373 if (ast_answer(chan)) 01374 return -1; 01375 peer->appl = "Bridged Call"; 01376 peer->data = chan->name; 01377 01378 /* copy the userfield from the B-leg to A-leg if applicable */ 01379 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) { 01380 char tmp[256]; 01381 if (!ast_strlen_zero(chan->cdr->userfield)) { 01382 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield); 01383 ast_cdr_appenduserfield(chan, tmp); 01384 } else 01385 ast_cdr_setuserfield(chan, peer->cdr->userfield); 01386 /* free the peer's cdr without ast_cdr_free complaining */ 01387 free(peer->cdr); 01388 peer->cdr = NULL; 01389 } 01390 01391 for (;;) { 01392 struct ast_channel *other; /* used later */ 01393 01394 res = ast_channel_bridge(chan, peer, config, &f, &who); 01395 01396 if (config->feature_timer) { 01397 /* Update time limit for next pass */ 01398 diff = ast_tvdiff_ms(ast_tvnow(), config->start_time); 01399 config->feature_timer -= diff; 01400 if (hasfeatures) { 01401 /* Running on backup config, meaning a feature might be being 01402 activated, but that's no excuse to keep things going 01403 indefinitely! */ 01404 if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) { 01405 if (option_debug) 01406 ast_log(LOG_DEBUG, "Timed out, realtime this time!\n"); 01407 config->feature_timer = 0; 01408 who = chan; 01409 if (f) 01410 ast_frfree(f); 01411 f = NULL; 01412 res = 0; 01413 } else if (config->feature_timer <= 0) { 01414 /* Not *really* out of time, just out of time for 01415 digits to come in for features. */ 01416 if (option_debug) 01417 ast_log(LOG_DEBUG, "Timed out for feature!\n"); 01418 if (!ast_strlen_zero(peer_featurecode)) { 01419 ast_dtmf_stream(chan, peer, peer_featurecode, 0); 01420 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 01421 } 01422 if (!ast_strlen_zero(chan_featurecode)) { 01423 ast_dtmf_stream(peer, chan, chan_featurecode, 0); 01424 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 01425 } 01426 if (f) 01427 ast_frfree(f); 01428 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01429 if (!hasfeatures) { 01430 /* Restore original (possibly time modified) bridge config */ 01431 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01432 memset(&backup_config, 0, sizeof(backup_config)); 01433 } 01434 hadfeatures = hasfeatures; 01435 /* Continue as we were */ 01436 continue; 01437 } else if (!f) { 01438 /* The bridge returned without a frame and there is a feature in progress. 01439 * However, we don't think the feature has quite yet timed out, so just 01440 * go back into the bridge. */ 01441 continue; 01442 } 01443 } else { 01444 if (config->feature_timer <=0) { 01445 /* We ran out of time */ 01446 config->feature_timer = 0; 01447 who = chan; 01448 if (f) 01449 ast_frfree(f); 01450 f = NULL; 01451 res = 0; 01452 } 01453 } 01454 } 01455 if (res < 0) { 01456 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 01457 return -1; 01458 } 01459 01460 if (!f || (f->frametype == AST_FRAME_CONTROL && 01461 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 01462 f->subclass == AST_CONTROL_CONGESTION ) ) ) { 01463 res = -1; 01464 break; 01465 } 01466 /* many things should be sent to the 'other' channel */ 01467 other = (who == chan) ? peer : chan; 01468 if (f->frametype == AST_FRAME_CONTROL) { 01469 switch (f->subclass) { 01470 case AST_CONTROL_RINGING: 01471 case AST_CONTROL_FLASH: 01472 case -1: 01473 ast_indicate(other, f->subclass); 01474 break; 01475 case AST_CONTROL_HOLD: 01476 case AST_CONTROL_UNHOLD: 01477 ast_indicate_data(other, f->subclass, f->data, f->datalen); 01478 break; 01479 case AST_CONTROL_OPTION: 01480 aoh = f->data; 01481 /* Forward option Requests */ 01482 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 01483 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 01484 f->datalen - sizeof(struct ast_option_header), 0); 01485 } 01486 break; 01487 } 01488 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 01489 /* eat it */ 01490 } else if (f->frametype == AST_FRAME_DTMF) { 01491 char *featurecode; 01492 int sense; 01493 01494 hadfeatures = hasfeatures; 01495 /* This cannot overrun because the longest feature is one shorter than our buffer */ 01496 if (who == chan) { 01497 sense = FEATURE_SENSE_CHAN; 01498 featurecode = chan_featurecode; 01499 } else { 01500 sense = FEATURE_SENSE_PEER; 01501 featurecode = peer_featurecode; 01502 } 01503 /*! append the event to featurecode. we rely on the string being zero-filled, and 01504 * not overflowing it. 01505 * \todo XXX how do we guarantee the latter ? 01506 */ 01507 featurecode[strlen(featurecode)] = f->subclass; 01508 /* Get rid of the frame before we start doing "stuff" with the channels */ 01509 ast_frfree(f); 01510 f = NULL; 01511 config->feature_timer = backup_config.feature_timer; 01512 res = ast_feature_interpret(chan, peer, config, featurecode, sense); 01513 switch(res) { 01514 case FEATURE_RETURN_PASSDIGITS: 01515 ast_dtmf_stream(other, who, featurecode, 0); 01516 /* Fall through */ 01517 case FEATURE_RETURN_SUCCESS: 01518 memset(featurecode, 0, sizeof(chan_featurecode)); 01519 break; 01520 } 01521 if (res >= FEATURE_RETURN_PASSDIGITS) { 01522 res = 0; 01523 } else 01524 break; 01525 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01526 if (hadfeatures && !hasfeatures) { 01527 /* Restore backup */ 01528 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01529 memset(&backup_config, 0, sizeof(struct ast_bridge_config)); 01530 } else if (hasfeatures) { 01531 if (!hadfeatures) { 01532 /* Backup configuration */ 01533 memcpy(&backup_config, config, sizeof(struct ast_bridge_config)); 01534 /* Setup temporary config options */ 01535 config->play_warning = 0; 01536 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 01537 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 01538 config->warning_freq = 0; 01539 config->warning_sound = NULL; 01540 config->end_sound = NULL; 01541 config->start_sound = NULL; 01542 config->firstpass = 0; 01543 } 01544 config->start_time = ast_tvnow(); 01545 config->feature_timer = featuredigittimeout; 01546 if (option_debug) 01547 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer); 01548 } 01549 } 01550 if (f) 01551 ast_frfree(f); 01552 01553 } 01554 01555 /* arrange the cdrs */ 01556 bridge_cdr = ast_cdr_alloc(); 01557 if (bridge_cdr) { 01558 if (chan->cdr && peer->cdr) { /* both of them? merge */ 01559 ast_cdr_init(bridge_cdr,chan); /* seems more logicaller to use the destination as a base, but, really, it's random */ 01560 ast_cdr_start(bridge_cdr); /* now is the time to start */ 01561 01562 /* absorb the channel cdr */ 01563 ast_cdr_merge(bridge_cdr, chan->cdr); 01564 if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED)) 01565 ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */ 01566 01567 /* absorb the peer cdr */ 01568 ast_cdr_merge(bridge_cdr, peer->cdr); 01569 if (ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED)) 01570 ast_cdr_discard(peer->cdr); /* if locked cdrs are in peer, they are taken over in the merge */ 01571 01572 peer->cdr = NULL; 01573 chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */ 01574 } else if (chan->cdr) { 01575 /* take the cdr from the channel - literally */ 01576 ast_cdr_init(bridge_cdr,chan); 01577 /* absorb this data */ 01578 ast_cdr_merge(bridge_cdr, chan->cdr); 01579 if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED)) 01580 ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */ 01581 chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */ 01582 } else if (peer->cdr) { 01583 /* take the cdr from the peer - literally */ 01584 ast_cdr_init(bridge_cdr,peer); 01585 /* absorb this data */ 01586 ast_cdr_merge(bridge_cdr, peer->cdr); 01587 if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED)) 01588 ast_cdr_discard(peer->cdr); /* if locked cdrs are in chan, they are taken over in the merge */ 01589 peer->cdr = NULL; 01590 peer->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */ 01591 } else { 01592 /* make up a new cdr */ 01593 ast_cdr_init(bridge_cdr,chan); /* eh, just pick one of them */ 01594 chan->cdr = bridge_cdr; /* */ 01595 } 01596 if (ast_strlen_zero(bridge_cdr->dstchannel)) { 01597 if (strcmp(bridge_cdr->channel, peer->name) != 0) 01598 ast_cdr_setdestchan(bridge_cdr, peer->name); 01599 else 01600 ast_cdr_setdestchan(bridge_cdr, chan->name); 01601 } 01602 } 01603 return res; 01604 }
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 1043 of file res_features.c.
References ast_copy_flags, AST_FLAGS_ALL, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verbose(), ast_call_feature::exten, exten, ast_call_feature::feature_mask, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_STOREDIGITS, FEATURE_SENSE_CHAN, ast_bridge_config::features_callee, ast_bridge_config::features_caller, FEATURES_COUNT, find_dynamic_feature(), ast_flags::flags, LOG_DEBUG, ast_call_feature::operation, option_debug, option_verbose, pbx_builtin_getvar_helper(), ast_call_feature::sname, strsep(), and VERBOSE_PREFIX_3.
Referenced by ast_bridge_call().
01044 { 01045 int x; 01046 struct ast_flags features; 01047 int res = FEATURE_RETURN_PASSDIGITS; 01048 struct ast_call_feature *feature; 01049 const char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES"); 01050 char *tmp, *tok; 01051 01052 if (sense == FEATURE_SENSE_CHAN) 01053 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL); 01054 else 01055 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL); 01056 if (option_debug > 2) 01057 ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags); 01058 01059 ast_rwlock_rdlock(&features_lock); 01060 for (x = 0; x < FEATURES_COUNT; x++) { 01061 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) && 01062 !ast_strlen_zero(builtin_features[x].exten)) { 01063 /* Feature is up for consideration */ 01064 if (!strcmp(builtin_features[x].exten, code)) { 01065 res = builtin_features[x].operation(chan, peer, config, code, sense); 01066 break; 01067 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) { 01068 if (res == FEATURE_RETURN_PASSDIGITS) 01069 res = FEATURE_RETURN_STOREDIGITS; 01070 } 01071 } 01072 } 01073 ast_rwlock_unlock(&features_lock); 01074 01075 if (ast_strlen_zero(dynamic_features)) 01076 return res; 01077 01078 tmp = ast_strdupa(dynamic_features); 01079 01080 while ((tok = strsep(&tmp, "#"))) { 01081 AST_LIST_LOCK(&feature_list); 01082 if (!(feature = find_dynamic_feature(tok))) { 01083 AST_LIST_UNLOCK(&feature_list); 01084 continue; 01085 } 01086 01087 /* Feature is up for consideration */ 01088 if (!strcmp(feature->exten, code)) { 01089 if (option_verbose > 2) 01090 ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok); 01091 res = feature->operation(chan, peer, config, code, sense); 01092 AST_LIST_UNLOCK(&feature_list); 01093 break; 01094 } else if (!strncmp(feature->exten, code, strlen(code))) 01095 res = FEATURE_RETURN_STOREDIGITS; 01096 01097 AST_LIST_UNLOCK(&feature_list); 01098 } 01099 01100 return res; 01101 }
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, read] |
Definition at line 1146 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(), ast_channel::cdr, ast_call_feature::exten, f, FEATURES_COUNT, ast_frame::frametype, ast_channel::hangupcause, len, LOG_NOTICE, LOG_WARNING, option_verbose, pbx_builtin_setvar_helper(), ast_frame::subclass, and VERBOSE_PREFIX_3.
Referenced by builtin_atxfer().
01147 { 01148 int state = 0; 01149 int cause = 0; 01150 int to; 01151 struct ast_channel *chan; 01152 struct ast_channel *monitor_chans[2]; 01153 struct ast_channel *active_channel; 01154 int res = 0, ready = 0; 01155 01156 if ((chan = ast_request(type, format, data, &cause))) { 01157 ast_set_callerid(chan, cid_num, cid_name, cid_num); 01158 ast_channel_inherit_variables(caller, chan); 01159 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name); 01160 if (!chan->cdr) { 01161 chan->cdr=ast_cdr_alloc(); 01162 if (chan->cdr) { 01163 ast_cdr_init(chan->cdr, chan); /* initilize our channel's cdr */ 01164 ast_cdr_start(chan->cdr); 01165 } 01166 } 01167 01168 if (!ast_call(chan, data, timeout)) { 01169 struct timeval started; 01170 int x, len = 0; 01171 char *disconnect_code = NULL, *dialed_code = NULL; 01172 01173 ast_indicate(caller, AST_CONTROL_RINGING); 01174 /* support dialing of the featuremap disconnect code while performing an attended tranfer */ 01175 ast_rwlock_rdlock(&features_lock); 01176 for (x = 0; x < FEATURES_COUNT; x++) { 01177 if (strcasecmp(builtin_features[x].sname, "disconnect")) 01178 continue; 01179 01180 disconnect_code = builtin_features[x].exten; 01181 len = strlen(disconnect_code) + 1; 01182 dialed_code = alloca(len); 01183 memset(dialed_code, 0, len); 01184 break; 01185 } 01186 ast_rwlock_unlock(&features_lock); 01187 x = 0; 01188 started = ast_tvnow(); 01189 to = timeout; 01190 while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) { 01191 struct ast_frame *f = NULL; 01192 01193 monitor_chans[0] = caller; 01194 monitor_chans[1] = chan; 01195 active_channel = ast_waitfor_n(monitor_chans, 2, &to); 01196 01197 /* see if the timeout has been violated */ 01198 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) { 01199 state = AST_CONTROL_UNHOLD; 01200 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n"); 01201 break; /*doh! timeout*/ 01202 } 01203 01204 if (!active_channel) 01205 continue; 01206 01207 if (chan && (chan == active_channel)){ 01208 f = ast_read(chan); 01209 if (f == NULL) { /*doh! where'd he go?*/ 01210 state = AST_CONTROL_HANGUP; 01211 res = 0; 01212 break; 01213 } 01214 01215 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) { 01216 if (f->subclass == AST_CONTROL_RINGING) { 01217 state = f->subclass; 01218 if (option_verbose > 2) 01219 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name); 01220 ast_indicate(caller, AST_CONTROL_RINGING); 01221 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) { 01222 state = f->subclass; 01223 if (option_verbose > 2) 01224 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name); 01225 ast_indicate(caller, AST_CONTROL_BUSY); 01226 ast_frfree(f); 01227 f = NULL; 01228 break; 01229 } else if (f->subclass == AST_CONTROL_ANSWER) { 01230 /* This is what we are hoping for */ 01231 state = f->subclass; 01232 ast_frfree(f); 01233 f = NULL; 01234 ready=1; 01235 break; 01236 } else { 01237 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass); 01238 } 01239 /* else who cares */ 01240 } 01241 01242 } else if (caller && (active_channel == caller)) { 01243 f = ast_read(caller); 01244 if (f == NULL) { /*doh! where'd he go?*/ 01245 if (caller->_softhangup && !chan->_softhangup) { 01246 /* make this a blind transfer */ 01247 ready = 1; 01248 break; 01249 } 01250 state = AST_CONTROL_HANGUP; 01251 res = 0; 01252 break; 01253 } 01254 01255 if (f->frametype == AST_FRAME_DTMF) { 01256 dialed_code[x++] = f->subclass; 01257 dialed_code[x] = '\0'; 01258 if (strlen(dialed_code) == len) { 01259 x = 0; 01260 } else if (x && strncmp(dialed_code, disconnect_code, x)) { 01261 x = 0; 01262 dialed_code[x] = '\0'; 01263 } 01264 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) { 01265 /* Caller Canceled the call */ 01266 state = AST_CONTROL_UNHOLD; 01267 ast_frfree(f); 01268 f = NULL; 01269 break; 01270 } 01271 } 01272 } 01273 if (f) 01274 ast_frfree(f); 01275 } /* end while */ 01276 } else 01277 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data); 01278 } else { 01279 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data); 01280 switch(cause) { 01281 case AST_CAUSE_BUSY: 01282 state = AST_CONTROL_BUSY; 01283 break; 01284 case AST_CAUSE_CONGESTION: 01285 state = AST_CONTROL_CONGESTION; 01286 break; 01287 } 01288 } 01289 01290 ast_indicate(caller, -1); 01291 if (chan && ready) { 01292 if (chan->_state == AST_STATE_UP) 01293 state = AST_CONTROL_ANSWER; 01294 res = 0; 01295 } else if(chan) { 01296 res = -1; 01297 ast_hangup(chan); 01298 chan = NULL; 01299 } else { 01300 res = -1; 01301 } 01302 01303 if (outstate) 01304 *outstate = state; 01305 01306 if (chan && res <= 0) { 01307 if (chan->cdr || (chan->cdr = ast_cdr_alloc())) { 01308 char tmp[256]; 01309 ast_cdr_init(chan->cdr, chan); 01310 snprintf(tmp, 256, "%s/%s", type, (char *)data); 01311 ast_cdr_setapp(chan->cdr,"Dial",tmp); 01312 ast_cdr_update(chan); 01313 ast_cdr_start(chan->cdr); 01314 ast_cdr_end(chan->cdr); 01315 /* If the cause wasn't handled properly */ 01316 if (ast_cdr_disposition(chan->cdr,chan->hangupcause)) 01317 ast_cdr_failed(chan->cdr); 01318 } else { 01319 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n"); 01320 } 01321 } 01322 01323 return chan; 01324 }
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.
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.
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(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::context, parkeduser::context, ast_channel::data, EVENT_FLAG_CALL, ast_channel::exten, parkeduser::exten, free, LOG_ERROR, LOG_WARNING, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, manager_event(), parkeduser::next, notify_metermaids(), parkeduser::notquiteyet, option_verbose, parkeduser::parkingexten, parkeduser::parkingnum, parkeduser::parkingtime, pbx_builtin_getvar_helper(), parkeduser::peername, ast_channel::priority, parkeduser::priority, S_OR, parkeduser::start, strdup, and VERBOSE_PREFIX_2.
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.
00156 { 00157 return parking_ext; 00158 }
int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
Definition at line 2134 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.
02135 { 02136 struct ast_channel *cur = NULL; 02137 int res = -1; 02138 02139 while ( (cur = ast_channel_walk_locked(cur)) != NULL) { 02140 if (!cur->pbx && 02141 (cur != chan) && 02142 (chan->pickupgroup & cur->callgroup) && 02143 ((cur->_state == AST_STATE_RINGING) || 02144 (cur->_state == AST_STATE_RING))) { 02145 break; 02146 } 02147 ast_channel_unlock(cur); 02148 } 02149 if (cur) { 02150 if (option_debug) 02151 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name); 02152 res = ast_answer(chan); 02153 if (res) 02154 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); 02155 res = ast_queue_control(chan, AST_CONTROL_ANSWER); 02156 if (res) 02157 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); 02158 res = ast_channel_masquerade(cur, chan); 02159 if (res) 02160 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */ 02161 ast_channel_unlock(cur); 02162 } else { 02163 if (option_debug) 02164 ast_log(LOG_DEBUG, "No call pickup possible...\n"); 02165 } 02166 return res; 02167 }
char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 160 of file res_features.c.
00161 { 00162 return pickup_ext; 00163 }
void ast_register_feature | ( | struct ast_call_feature * | feature | ) |
register new feature into feature_list
register new feature into feature_set
Definition at line 895 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.
00896 { 00897 if (!feature) { 00898 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 00899 return; 00900 } 00901 00902 AST_LIST_LOCK(&feature_list); 00903 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry); 00904 AST_LIST_UNLOCK(&feature_list); 00905 00906 if (option_verbose >= 2) 00907 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname); 00908 }
AST_RWLOCK_DEFINE_STATIC | ( | features_lock | ) |
void ast_unregister_feature | ( | struct ast_call_feature * | feature | ) |
unregister feature from feature_list
unregister feature from feature_set
Definition at line 911 of file res_features.c.
References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free.
00912 { 00913 if (!feature) 00914 return; 00915 00916 AST_LIST_LOCK(&feature_list); 00917 AST_LIST_REMOVE(&feature_list,feature,feature_entry); 00918 AST_LIST_UNLOCK(&feature_list); 00919 free(feature); 00920 }
static void ast_unregister_features | ( | void | ) | [static] |
Remove all features in the list.
Definition at line 923 of file res_features.c.
References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and free.
Referenced by load_config().
00924 { 00925 struct ast_call_feature *feature; 00926 00927 AST_LIST_LOCK(&feature_list); 00928 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry))) 00929 free(feature); 00930 AST_LIST_UNLOCK(&feature_list); 00931 }
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 741 of file res_features.c.
References ast_channel::_softhangup, ast_channel::_state, ast_app_dtget(), ast_autoservice_start(), ast_autoservice_stop(), ast_best_codec(), ast_bridge_call(), ast_bridge_call_thread_launch(), ast_calloc, ast_channel_alloc(), ast_channel_masquerade(), ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, AST_DIGIT_ANY, ast_exists_extension(), ast_explicit_goto(), AST_FEATURE_DISCONNECT, ast_feature_request_and_dial(), AST_FLAGS_ALL, ast_frfree(), ast_hangup(), ast_indicate(), ast_log(), ast_read(), ast_set_flag, AST_STATE_DOWN, AST_STATE_UP, ast_stream_and_wait(), ast_waitfordigit(), ast_bridge_thread_obj::bconfig, ast_bridge_thread_obj::chan, check_compat(), ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::context, ast_channel::exten, f, FEATURE_RETURN_SUCCESS, ast_bridge_config::features_callee, ast_bridge_config::features_caller, finishup(), LOG_DEBUG, LOG_WARNING, ast_channel::nativeformats, option_debug, ast_bridge_thread_obj::peer, ast_channel::priority, ast_channel::readformat, real_ctx(), set_peers(), and ast_channel::writeformat.
00742 { 00743 struct ast_channel *transferer; 00744 struct ast_channel *transferee; 00745 const char *transferer_real_context; 00746 char xferto[256] = ""; 00747 int res; 00748 int outstate=0; 00749 struct ast_channel *newchan; 00750 struct ast_channel *xferchan; 00751 struct ast_bridge_thread_obj *tobj; 00752 struct ast_bridge_config bconfig; 00753 struct ast_frame *f; 00754 int l; 00755 00756 if (option_debug) 00757 ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense); 00758 set_peers(&transferer, &transferee, peer, chan, sense); 00759 transferer_real_context = real_ctx(transferer, transferee); 00760 /* Start autoservice on chan while we talk to the originator */ 00761 ast_autoservice_start(transferee); 00762 ast_indicate(transferee, AST_CONTROL_HOLD); 00763 00764 /* Transfer */ 00765 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY); 00766 if (res < 0) { 00767 finishup(transferee); 00768 return res; 00769 } 00770 if (res > 0) /* If they've typed a digit already, handle it */ 00771 xferto[0] = (char) res; 00772 00773 /* this is specific of atxfer */ 00774 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 00775 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */ 00776 finishup(transferee); 00777 return res; 00778 } 00779 if (res == 0) { 00780 ast_log(LOG_WARNING, "Did not read data.\n"); 00781 finishup(transferee); 00782 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, "")) 00783 return -1; 00784 return FEATURE_RETURN_SUCCESS; 00785 } 00786 00787 /* valid extension, res == 1 */ 00788 if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) { 00789 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context); 00790 finishup(transferee); 00791 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, "")) 00792 return -1; 00793 return FEATURE_RETURN_SUCCESS; 00794 } 00795 00796 l = strlen(xferto); 00797 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); /* append context */ 00798 newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats), 00799 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name); 00800 ast_indicate(transferer, -1); 00801 if (!newchan) { 00802 finishup(transferee); 00803 /* any reason besides user requested cancel and busy triggers the failed sound */ 00804 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY && 00805 ast_stream_and_wait(transferer, xferfailsound, transferer->language, "")) 00806 return -1; 00807 return FEATURE_RETURN_SUCCESS; 00808 } 00809 00810 if (check_compat(transferer, newchan)) 00811 return -1; 00812 memset(&bconfig,0,sizeof(struct ast_bridge_config)); 00813 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 00814 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 00815 res = ast_bridge_call(transferer, newchan, &bconfig); 00816 if (newchan->_softhangup || !transferer->_softhangup) { 00817 ast_hangup(newchan); 00818 if (ast_stream_and_wait(transferer, xfersound, transferer->language, "")) 00819 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 00820 finishup(transferee); 00821 transferer->_softhangup = 0; 00822 return FEATURE_RETURN_SUCCESS; 00823 } 00824 00825 if (check_compat(transferee, newchan)) 00826 return -1; 00827 00828 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00829 00830 if ((ast_autoservice_stop(transferee) < 0) 00831 || (ast_waitfordigit(transferee, 100) < 0) 00832 || (ast_waitfordigit(newchan, 100) < 0) 00833 || ast_check_hangup(transferee) 00834 || ast_check_hangup(newchan)) { 00835 ast_hangup(newchan); 00836 return -1; 00837 } 00838 00839 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name); 00840 if (!xferchan) { 00841 ast_hangup(newchan); 00842 return -1; 00843 } 00844 /* Make formats okay */ 00845 xferchan->readformat = transferee->readformat; 00846 xferchan->writeformat = transferee->writeformat; 00847 ast_channel_masquerade(xferchan, transferee); 00848 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority); 00849 xferchan->_state = AST_STATE_UP; 00850 ast_clear_flag(xferchan, AST_FLAGS_ALL); 00851 xferchan->_softhangup = 0; 00852 00853 if ((f = ast_read(xferchan))) 00854 ast_frfree(f); 00855 00856 newchan->_state = AST_STATE_UP; 00857 ast_clear_flag(newchan, AST_FLAGS_ALL); 00858 newchan->_softhangup = 0; 00859 00860 tobj = ast_calloc(1, sizeof(struct ast_bridge_thread_obj)); 00861 if (!tobj) { 00862 ast_hangup(xferchan); 00863 ast_hangup(newchan); 00864 return -1; 00865 } 00866 tobj->chan = xferchan; 00867 tobj->peer = newchan; 00868 tobj->bconfig = *config; 00869 00870 if (ast_stream_and_wait(newchan, xfersound, newchan->language, "")) 00871 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 00872 ast_bridge_call_thread_launch(tobj); 00873 return -1; /* XXX meaning the channel is bridged ? */ 00874 }
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, 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(), ast_channel::cdr, check_goto_on_transfer(), ast_channel::cid, ast_callerid::cid_num, FEATURE_RETURN_SUCCESS, finishup(), LOG_WARNING, option_verbose, ast_channel::pbx, pbx_builtin_setvar_helper(), real_ctx(), set_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 res = -1; 00704 00705 if (option_verbose > 2) 00706 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n" 00707 ,transferee->name, xferto, transferer_real_context); 00708 if (ast_async_goto(transferee, transferer_real_context, xferto, 1)) 00709 ast_log(LOG_WARNING, "Async goto failed :-(\n"); 00710 check_goto_on_transfer(transferer); 00711 return res; 00712 } else { 00713 if (option_verbose > 2) 00714 ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context); 00715 } 00716 if (ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0 ) { 00717 finishup(transferee); 00718 return -1; 00719 } 00720 ast_stopstream(transferer); 00721 res = finishup(transferee); 00722 if (res) { 00723 if (option_verbose > 1) 00724 ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name); 00725 return res; 00726 } 00727 return FEATURE_RETURN_SUCCESS; 00728 }
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_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 730 of file res_features.c.
References ast_channel_make_compatible(), ast_hangup(), ast_log(), and LOG_WARNING.
Referenced by builtin_atxfer().
00731 { 00732 if (ast_channel_make_compatible(c, newchan) < 0) { 00733 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", 00734 c->name, newchan->name); 00735 ast_hangup(newchan); 00736 return -1; 00737 } 00738 return 0; 00739 }
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 1621 of file res_features.c.
References ast_add_extension2(), ast_clear_flag, ast_context_create(), ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, ast_free, ast_frfree(), ast_hangup(), ast_indicate(), ast_indicate_data(), ast_log(), AST_MAX_EXTENSION, AST_MAX_FDS, ast_mutex_lock(), ast_mutex_unlock(), ast_pbx_start(), ast_read(), ast_select(), ast_set_flag, ast_strdupa, ast_strlen_zero(), ast_verbose(), parkeduser::chan, ast_channel::context, parkeduser::context, ast_channel::exten, parkeduser::exten, f, ast_channel::fdno, ast_channel::fds, ast_frame::frametype, free, ast_channel::generatordata, LOG_DEBUG, LOG_ERROR, LOG_WARNING, parkeduser::moh_trys, parkeduser::next, notify_metermaids(), parkeduser::notquiteyet, option_debug, option_verbose, parkeduser::parkingexten, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, post_manager_event(), ast_channel::priority, parkeduser::priority, S_OR, set_c_e_p(), parkeduser::start, strdup, ast_frame::subclass, and VERBOSE_PREFIX_2.
Referenced by load_module().
01622 { 01623 fd_set rfds, efds; /* results from previous select, to be preserved across loops. */ 01624 FD_ZERO(&rfds); 01625 FD_ZERO(&efds); 01626 01627 for (;;) { 01628 struct parkeduser *pu, *pl, *pt = NULL; 01629 int ms = -1; /* select timeout, uninitialized */ 01630 int max = -1; /* max fd, none there yet */ 01631 fd_set nrfds, nefds; /* args for the next select */ 01632 FD_ZERO(&nrfds); 01633 FD_ZERO(&nefds); 01634 01635 ast_mutex_lock(&parking_lock); 01636 pl = NULL; 01637 pu = parkinglot; 01638 /* navigate the list with prev-cur pointers to support removals */ 01639 while (pu) { 01640 struct ast_channel *chan = pu->chan; /* shorthand */ 01641 int tms; /* timeout for this item */ 01642 int x; /* fd index in channel */ 01643 struct ast_context *con; 01644 01645 if (pu->notquiteyet) { /* Pretend this one isn't here yet */ 01646 pl = pu; 01647 pu = pu->next; 01648 continue; 01649 } 01650 tms = ast_tvdiff_ms(ast_tvnow(), pu->start); 01651 if (tms > pu->parkingtime) { 01652 ast_indicate(chan, AST_CONTROL_UNHOLD); 01653 /* Get chan, exten from derived kludge */ 01654 if (pu->peername[0]) { 01655 char *peername = ast_strdupa(pu->peername); 01656 char *cp = strrchr(peername, '-'); 01657 if (cp) 01658 *cp = 0; 01659 con = ast_context_find(parking_con_dial); 01660 if (!con) { 01661 con = ast_context_create(NULL, parking_con_dial, registrar); 01662 if (!con) 01663 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial); 01664 } 01665 if (con) { 01666 char returnexten[AST_MAX_EXTENSION]; 01667 snprintf(returnexten, sizeof(returnexten), "%s||t", peername); 01668 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar); 01669 } 01670 set_c_e_p(chan, parking_con_dial, peername, 1); 01671 } else { 01672 /* They've been waiting too long, send them back to where they came. Theoretically they 01673 should have their original extensions and such, but we copy to be on the safe side */ 01674 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 01675 } 01676 01677 post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan); 01678 01679 if (option_verbose > 1) 01680 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); 01681 /* Start up the PBX, or hang them up */ 01682 if (ast_pbx_start(chan)) { 01683 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name); 01684 ast_hangup(chan); 01685 } 01686 /* And take them out of the parking lot */ 01687 if (pl) 01688 pl->next = pu->next; 01689 else 01690 parkinglot = pu->next; 01691 pt = pu; 01692 pu = pu->next; 01693 con = ast_context_find(parking_con); 01694 if (con) { 01695 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL)) 01696 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 01697 else 01698 notify_metermaids(pt->parkingexten, parking_con); 01699 } else 01700 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 01701 free(pt); 01702 } else { /* still within parking time, process descriptors */ 01703 for (x = 0; x < AST_MAX_FDS; x++) { 01704 struct ast_frame *f; 01705 01706 if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds))) 01707 continue; /* nothing on this descriptor */ 01708 01709 if (FD_ISSET(chan->fds[x], &efds)) 01710 ast_set_flag(chan, AST_FLAG_EXCEPTION); 01711 else 01712 ast_clear_flag(chan, AST_FLAG_EXCEPTION); 01713 chan->fdno = x; 01714 01715 /* See if they need servicing */ 01716 f = ast_read(chan); 01717 if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP)) { 01718 if (f) 01719 ast_frfree(f); 01720 post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan); 01721 01722 /* There's a problem, hang them up*/ 01723 if (option_verbose > 1) 01724 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name); 01725 ast_hangup(chan); 01726 /* And take them out of the parking lot */ 01727 if (pl) 01728 pl->next = pu->next; 01729 else 01730 parkinglot = pu->next; 01731 pt = pu; 01732 pu = pu->next; 01733 con = ast_context_find(parking_con); 01734 if (con) { 01735 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL)) 01736 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 01737 else 01738 notify_metermaids(pt->parkingexten, parking_con); 01739 } else 01740 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 01741 free(pt); 01742 break; 01743 } else { 01744 /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ 01745 ast_frfree(f); 01746 if (pu->moh_trys < 3 && !chan->generatordata) { 01747 if (option_debug) 01748 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n"); 01749 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 01750 S_OR(parkmohclass, NULL), 01751 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 01752 pu->moh_trys++; 01753 } 01754 goto std; /*! \todo XXX Ick: jumping into an else statement??? XXX */ 01755 } 01756 01757 } /* end for */ 01758 if (x >= AST_MAX_FDS) { 01759 std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */ 01760 if (chan->fds[x] > -1) { 01761 FD_SET(chan->fds[x], &nrfds); 01762 FD_SET(chan->fds[x], &nefds); 01763 if (chan->fds[x] > max) 01764 max = chan->fds[x]; 01765 } 01766 } 01767 /* Keep track of our shortest wait */ 01768 if (tms < ms || ms < 0) 01769 ms = tms; 01770 pl = pu; 01771 pu = pu->next; 01772 } 01773 } 01774 } /* end while */ 01775 ast_mutex_unlock(&parking_lock); 01776 rfds = nrfds; 01777 efds = nefds; 01778 { 01779 struct timeval tv = ast_samp2tv(ms, 1000); 01780 /* Wait for something to happen */ 01781 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL); 01782 } 01783 pthread_testcancel(); 01784 } 01785 return NULL; /* Never reached */ 01786 }
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 947 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().
Referenced by load_config().
00948 { 00949 struct ast_app *app; 00950 struct ast_call_feature *feature; 00951 struct ast_channel *work, *idle; 00952 int res; 00953 00954 AST_LIST_LOCK(&feature_list); 00955 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) { 00956 if (!strcasecmp(feature->exten, code)) 00957 break; 00958 } 00959 AST_LIST_UNLOCK(&feature_list); 00960 00961 if (!feature) { /* shouldn't ever happen! */ 00962 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n"); 00963 return -1; 00964 } 00965 00966 if (sense == FEATURE_SENSE_CHAN) { 00967 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 00968 return FEATURE_RETURN_PASSDIGITS; 00969 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 00970 work = chan; 00971 idle = peer; 00972 } else { 00973 work = peer; 00974 idle = chan; 00975 } 00976 } else { 00977 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 00978 return FEATURE_RETURN_PASSDIGITS; 00979 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 00980 work = peer; 00981 idle = chan; 00982 } else { 00983 work = chan; 00984 idle = peer; 00985 } 00986 } 00987 00988 if (!(app = pbx_findapp(feature->app))) { 00989 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app); 00990 return -2; 00991 } 00992 00993 ast_autoservice_start(idle); 00994 00995 if (!ast_strlen_zero(feature->moh_class)) 00996 ast_moh_start(idle, feature->moh_class, NULL); 00997 00998 res = pbx_exec(work, app, feature->app_args); 00999 01000 if (!ast_strlen_zero(feature->moh_class)) 01001 ast_moh_stop(idle); 01002 01003 ast_autoservice_stop(idle); 01004 01005 if (res == AST_PBX_KEEPALIVE) 01006 return FEATURE_RETURN_PBX_KEEPALIVE; 01007 else if (res == AST_PBX_NO_HANGUP_PEER) 01008 return FEATURE_RETURN_NO_HANGUP_PEER; 01009 else if (res) 01010 return FEATURE_RETURN_SUCCESSBREAK; 01011 01012 return FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */ 01013 }
static struct ast_call_feature* find_dynamic_feature | ( | const char * | name | ) | [static, read] |
find a feature by name
Definition at line 934 of file res_features.c.
References AST_LIST_TRAVERSE, and ast_call_feature::sname.
Referenced by ast_feature_interpret(), load_config(), and set_config_flags().
00935 { 00936 struct ast_call_feature *tmp; 00937 00938 AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) { 00939 if (!strcasecmp(tmp->sname, name)) 00940 break; 00941 } 00942 00943 return tmp; 00944 }
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 1988 of file res_features.c.
References ast_cli(), ast_mutex_lock(), ast_mutex_unlock(), parkeduser::chan, parkeduser::context, parkeduser::exten, parkeduser::next, parkeduser::parkingexten, parkeduser::parkingtime, parkeduser::priority, RESULT_SUCCESS, and parkeduser::start.
01989 { 01990 struct parkeduser *cur; 01991 int numparked = 0; 01992 01993 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel" 01994 , "Context", "Extension", "Pri", "Timeout"); 01995 01996 ast_mutex_lock(&parking_lock); 01997 01998 for (cur = parkinglot; cur; cur = cur->next) { 01999 ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n" 02000 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten 02001 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)); 02002 02003 numparked++; 02004 } 02005 ast_mutex_unlock(&parking_lock); 02006 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : ""); 02007 02008 02009 return RESULT_SUCCESS; 02010 }
static int handle_showfeatures | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1947 of file res_features.c.
References ast_cli(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_pickup_ext(), ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_call_feature::default_exten, ast_call_feature::exten, exten, FEATURES_COUNT, ast_call_feature::fname, format, RESULT_SUCCESS, and ast_call_feature::sname.
01948 { 01949 int i; 01950 struct ast_call_feature *feature; 01951 char format[] = "%-25s %-7s %-7s\n"; 01952 01953 ast_cli(fd, format, "Builtin Feature", "Default", "Current"); 01954 ast_cli(fd, format, "---------------", "-------", "-------"); 01955 01956 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */ 01957 01958 ast_rwlock_rdlock(&features_lock); 01959 for (i = 0; i < FEATURES_COUNT; i++) 01960 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten); 01961 ast_rwlock_unlock(&features_lock); 01962 01963 ast_cli(fd, "\n"); 01964 ast_cli(fd, format, "Dynamic Feature", "Default", "Current"); 01965 ast_cli(fd, format, "---------------", "-------", "-------"); 01966 if (AST_LIST_EMPTY(&feature_list)) 01967 ast_cli(fd, "(none)\n"); 01968 else { 01969 AST_LIST_LOCK(&feature_list); 01970 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) 01971 ast_cli(fd, format, feature->sname, "no def", feature->exten); 01972 AST_LIST_UNLOCK(&feature_list); 01973 } 01974 ast_cli(fd, "\nCall parking\n"); 01975 ast_cli(fd, "------------\n"); 01976 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext); 01977 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con); 01978 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop); 01979 ast_cli(fd,"\n"); 01980 01981 return RESULT_SUCCESS; 01982 }
static int load_config | ( | void | ) | [static] |
Definition at line 2184 of file res_features.c.
References ast_call_feature::app, app, ast_call_feature::app_args, ast_add_extension2(), ast_calloc, ast_config_destroy(), ast_config_load(), ast_context_create(), ast_context_find(), ast_context_remove_extension2(), AST_FEATURE_FLAG_BYBOTH, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_NEEDSDTMF, AST_FEATURE_FLAG_ONPEER, AST_FEATURE_FLAG_ONSELF, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), AST_MAX_EXTENSION, AST_MODULE_LOAD_DECLINE, ast_parking_ext(), ast_register_feature(), ast_set_flag, ast_strdupa, ast_strlen_zero(), ast_true(), ast_unregister_features(), ast_variable_browse(), ast_verbose(), DEFAULT_FEATURE_DIGIT_TIMEOUT, DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER, DEFAULT_PARK_TIME, DEFAULT_TRANSFER_DIGIT_TIMEOUT, ast_call_feature::exten, exten, FEATURE_APP_ARGS_LEN, FEATURE_APP_LEN, feature_exec_app(), FEATURE_EXTEN_LEN, FEATURE_MOH_LEN, FEATURE_SNAME_LEN, find_dynamic_feature(), ast_variable::lineno, LOG_DEBUG, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, ast_variable::name, ast_variable::next, notify_metermaids(), ast_call_feature::operation, option_debug, option_verbose, park_add_hints(), remap_feature(), ast_call_feature::sname, strsep(), unmap_features(), ast_variable::value, var, and VERBOSE_PREFIX_2.
02185 { 02186 int start = 0, end = 0; 02187 int res; 02188 struct ast_context *con = NULL; 02189 struct ast_config *cfg = NULL; 02190 struct ast_variable *var = NULL; 02191 char old_parking_ext[AST_MAX_EXTENSION]; 02192 char old_parking_con[AST_MAX_EXTENSION] = ""; 02193 02194 if (!ast_strlen_zero(parking_con)) { 02195 strcpy(old_parking_ext, parking_ext); 02196 strcpy(old_parking_con, parking_con); 02197 } 02198 02199 /* Reset to defaults */ 02200 strcpy(parking_con, "parkedcalls"); 02201 strcpy(parking_con_dial, "park-dial"); 02202 strcpy(parking_ext, "700"); 02203 strcpy(pickup_ext, "*8"); 02204 strcpy(parkmohclass, "default"); 02205 courtesytone[0] = '\0'; 02206 strcpy(xfersound, "beep"); 02207 strcpy(xferfailsound, "pbx-invalid"); 02208 parking_start = 701; 02209 parking_stop = 750; 02210 parkfindnext = 0; 02211 adsipark = 0; 02212 parkaddhints = 0; 02213 02214 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 02215 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 02216 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 02217 02218 cfg = ast_config_load("features.conf"); 02219 if (!cfg) { 02220 ast_log(LOG_WARNING,"Could not load features.conf\n"); 02221 return AST_MODULE_LOAD_DECLINE; 02222 } 02223 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { 02224 if (!strcasecmp(var->name, "parkext")) { 02225 ast_copy_string(parking_ext, var->value, sizeof(parking_ext)); 02226 } else if (!strcasecmp(var->name, "context")) { 02227 ast_copy_string(parking_con, var->value, sizeof(parking_con)); 02228 } else if (!strcasecmp(var->name, "parkingtime")) { 02229 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) { 02230 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value); 02231 parkingtime = DEFAULT_PARK_TIME; 02232 } else 02233 parkingtime = parkingtime * 1000; 02234 } else if (!strcasecmp(var->name, "parkpos")) { 02235 if (sscanf(var->value, "%d-%d", &start, &end) != 2) { 02236 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); 02237 } else { 02238 parking_start = start; 02239 parking_stop = end; 02240 } 02241 } else if (!strcasecmp(var->name, "findslot")) { 02242 parkfindnext = (!strcasecmp(var->value, "next")); 02243 } else if (!strcasecmp(var->name, "parkinghints")) { 02244 parkaddhints = ast_true(var->value); 02245 } else if (!strcasecmp(var->name, "adsipark")) { 02246 adsipark = ast_true(var->value); 02247 } else if (!strcasecmp(var->name, "transferdigittimeout")) { 02248 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) { 02249 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value); 02250 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 02251 } else 02252 transferdigittimeout = transferdigittimeout * 1000; 02253 } else if (!strcasecmp(var->name, "featuredigittimeout")) { 02254 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) { 02255 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value); 02256 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 02257 } 02258 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) { 02259 if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) { 02260 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value); 02261 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 02262 } else 02263 atxfernoanswertimeout = atxfernoanswertimeout * 1000; 02264 } else if (!strcasecmp(var->name, "courtesytone")) { 02265 ast_copy_string(courtesytone, var->value, sizeof(courtesytone)); 02266 } else if (!strcasecmp(var->name, "parkedplay")) { 02267 if (!strcasecmp(var->value, "both")) 02268 parkedplay = 2; 02269 else if (!strcasecmp(var->value, "parked")) 02270 parkedplay = 1; 02271 else 02272 parkedplay = 0; 02273 } else if (!strcasecmp(var->name, "xfersound")) { 02274 ast_copy_string(xfersound, var->value, sizeof(xfersound)); 02275 } else if (!strcasecmp(var->name, "xferfailsound")) { 02276 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound)); 02277 } else if (!strcasecmp(var->name, "pickupexten")) { 02278 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext)); 02279 } else if (!strcasecmp(var->name, "parkedmusicclass")) { 02280 ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass)); 02281 } 02282 } 02283 02284 unmap_features(); 02285 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) { 02286 if (remap_feature(var->name, var->value)) 02287 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); 02288 } 02289 02290 /* Map a key combination to an application*/ 02291 ast_unregister_features(); 02292 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) { 02293 char *tmp_val = ast_strdupa(var->value); 02294 char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 02295 struct ast_call_feature *feature; 02296 02297 /* strsep() sets the argument to NULL if match not found, and it 02298 * is safe to use it with a NULL argument, so we don't check 02299 * between calls. 02300 */ 02301 exten = strsep(&tmp_val,","); 02302 activatedby = strsep(&tmp_val,","); 02303 app = strsep(&tmp_val,","); 02304 app_args = strsep(&tmp_val,","); 02305 moh_class = strsep(&tmp_val,","); 02306 02307 activateon = strsep(&activatedby, "/"); 02308 02309 /*! \todo XXX var_name or app_args ? */ 02310 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) { 02311 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n", 02312 app, exten, activateon, var->name); 02313 continue; 02314 } 02315 02316 AST_LIST_LOCK(&feature_list); 02317 if ((feature = find_dynamic_feature(var->name))) { 02318 AST_LIST_UNLOCK(&feature_list); 02319 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name); 02320 continue; 02321 } 02322 AST_LIST_UNLOCK(&feature_list); 02323 02324 if (!(feature = ast_calloc(1, sizeof(*feature)))) 02325 continue; 02326 02327 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN); 02328 ast_copy_string(feature->app, app, FEATURE_APP_LEN); 02329 ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN); 02330 02331 if (app_args) 02332 ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN); 02333 02334 if (moh_class) 02335 ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN); 02336 02337 ast_copy_string(feature->exten, exten, sizeof(feature->exten)); 02338 feature->operation = feature_exec_app; 02339 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF); 02340 02341 /* Allow caller and calle to be specified for backwards compatability */ 02342 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) 02343 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF); 02344 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) 02345 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER); 02346 else { 02347 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s'," 02348 " must be 'self', or 'peer'\n", var->name); 02349 continue; 02350 } 02351 02352 if (ast_strlen_zero(activatedby)) 02353 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 02354 else if (!strcasecmp(activatedby, "caller")) 02355 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER); 02356 else if (!strcasecmp(activatedby, "callee")) 02357 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE); 02358 else if (!strcasecmp(activatedby, "both")) 02359 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 02360 else { 02361 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s'," 02362 " must be 'caller', or 'callee', or 'both'\n", var->name); 02363 continue; 02364 } 02365 02366 ast_register_feature(feature); 02367 02368 if (option_verbose >= 1) 02369 ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten); 02370 } 02371 ast_config_destroy(cfg); 02372 02373 /* Remove the old parking extension */ 02374 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) { 02375 if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar)) 02376 notify_metermaids(old_parking_ext, old_parking_con); 02377 if (option_debug) 02378 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con); 02379 } 02380 02381 if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) { 02382 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); 02383 return -1; 02384 } 02385 res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar); 02386 if (parkaddhints) 02387 park_add_hints(parking_con, parking_start, parking_stop); 02388 if (!res) 02389 notify_metermaids(ast_parking_ext(), parking_con); 02390 return res; 02391 02392 }
static int load_module | ( | void | ) | [static] |
Definition at line 2399 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(), do_parking_thread(), EVENT_FLAG_CALL, load_config(), manager_park(), manager_parking_status(), metermaidstate(), park_call_exec(), and park_exec().
02400 { 02401 int res; 02402 02403 memset(parking_ext, 0, sizeof(parking_ext)); 02404 memset(parking_con, 0, sizeof(parking_con)); 02405 02406 if ((res = load_config())) 02407 return res; 02408 ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); 02409 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL); 02410 res = ast_register_application(parkedcall, park_exec, synopsis, descrip); 02411 if (!res) 02412 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2); 02413 if (!res) { 02414 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" ); 02415 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park, 02416 "Park a channel", mandescr_park); 02417 } 02418 02419 res |= ast_devstate_prov_add("Park", metermaidstate); 02420 02421 return res; 02422 }
static int manager_park | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 2079 of file res_features.c.
References ast_channel_unlock, ast_get_channel_by_name_locked(), ast_masq_park_call(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_strlen_zero(), astman_get_header(), astman_send_ack(), and astman_send_error().
Referenced by load_module().
02080 { 02081 const char *channel = astman_get_header(m, "Channel"); 02082 const char *channel2 = astman_get_header(m, "Channel2"); 02083 const char *timeout = astman_get_header(m, "Timeout"); 02084 char buf[BUFSIZ]; 02085 int to = 0; 02086 int res = 0; 02087 int parkExt = 0; 02088 struct ast_channel *ch1, *ch2; 02089 02090 if (ast_strlen_zero(channel)) { 02091 astman_send_error(s, m, "Channel not specified"); 02092 return 0; 02093 } 02094 02095 if (ast_strlen_zero(channel2)) { 02096 astman_send_error(s, m, "Channel2 not specified"); 02097 return 0; 02098 } 02099 02100 ch1 = ast_get_channel_by_name_locked(channel); 02101 if (!ch1) { 02102 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel); 02103 astman_send_error(s, m, buf); 02104 return 0; 02105 } 02106 02107 ch2 = ast_get_channel_by_name_locked(channel2); 02108 if (!ch2) { 02109 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2); 02110 astman_send_error(s, m, buf); 02111 ast_channel_unlock(ch1); 02112 return 0; 02113 } 02114 02115 if (!ast_strlen_zero(timeout)) { 02116 sscanf(timeout, "%d", &to); 02117 } 02118 02119 res = ast_masq_park_call(ch1, ch2, to, &parkExt); 02120 if (!res) { 02121 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT); 02122 astman_send_ack(s, m, "Park successful"); 02123 } else { 02124 astman_send_error(s, m, "Park failure"); 02125 } 02126 02127 ast_channel_unlock(ch1); 02128 ast_channel_unlock(ch2); 02129 02130 return 0; 02131 }
static int manager_parking_status | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Dump lot status.
Definition at line 2032 of file res_features.c.
References ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, parkeduser::next, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, RESULT_SUCCESS, S_OR, and parkeduser::start.
Referenced by load_module().
02033 { 02034 struct parkeduser *cur; 02035 const char *id = astman_get_header(m, "ActionID"); 02036 char idText[256] = ""; 02037 02038 if (!ast_strlen_zero(id)) 02039 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 02040 02041 astman_send_ack(s, m, "Parked calls will follow"); 02042 02043 ast_mutex_lock(&parking_lock); 02044 02045 for (cur = parkinglot; cur; cur = cur->next) { 02046 astman_append(s, "Event: ParkedCall\r\n" 02047 "Exten: %d\r\n" 02048 "Channel: %s\r\n" 02049 "From: %s\r\n" 02050 "Timeout: %ld\r\n" 02051 "CallerID: %s\r\n" 02052 "CallerIDName: %s\r\n" 02053 "%s" 02054 "\r\n", 02055 cur->parkingnum, cur->chan->name, cur->peername, 02056 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL), 02057 S_OR(cur->chan->cid.cid_num, ""), /* XXX in other places it is <unknown> */ 02058 S_OR(cur->chan->cid.cid_name, ""), 02059 idText); 02060 } 02061 02062 astman_append(s, 02063 "Event: ParkedCallsComplete\r\n" 02064 "%s" 02065 "\r\n",idText); 02066 02067 ast_mutex_unlock(&parking_lock); 02068 02069 return RESULT_SUCCESS; 02070 }
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(), load_config(), 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 2170 of file res_features.c.
References ast_add_extension(), AST_MAX_EXTENSION, exten, and PRIORITY_HINT.
Referenced by load_config().
02171 { 02172 int numext; 02173 char device[AST_MAX_EXTENSION]; 02174 char exten[10]; 02175 02176 for (numext = start; numext <= stop; numext++) { 02177 snprintf(exten, sizeof(exten), "%d", numext); 02178 snprintf(device, sizeof(device), "park:%s@%s", exten, context); 02179 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar); 02180 } 02181 }
static int park_call_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Park a call.
Definition at line 1789 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_channel::exten, and ast_channel::priority.
Referenced by load_module().
01790 { 01791 /* Data is unused at the moment but could contain a parking 01792 lot context eventually */ 01793 int res = 0; 01794 struct ast_module_user *u; 01795 01796 u = ast_module_user_add(chan); 01797 01798 /* Setup the exten/priority to be s/1 since we don't know 01799 where this call should return */ 01800 strcpy(chan->exten, "s"); 01801 chan->priority = 1; 01802 /* Answer if call is not up */ 01803 if (chan->_state != AST_STATE_UP) 01804 res = ast_answer(chan); 01805 /* Sleep to allow VoIP streams to settle down */ 01806 if (!res) 01807 res = ast_safe_sleep(chan, 1000); 01808 /* Park the call */ 01809 if (!res) 01810 res = ast_park_call(chan, chan, 0, NULL); 01811 01812 ast_module_user_remove(u); 01813 01814 return !res ? AST_PBX_KEEPALIVE : res; 01815 }
static int park_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Pickup parked call.
Definition at line 1818 of file res_features.c.
References ast_channel::_state, ast_answer(), ast_bridge_call(), ast_cdr_setdestchan(), ast_channel_make_compatible(), ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_UNHOLD, AST_FEATURE_REDIRECT, ast_hangup(), ast_indicate(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_mutex_lock(), ast_mutex_unlock(), AST_PBX_NO_HANGUP_PEER, ast_set_flag, AST_STATE_UP, ast_stream_and_wait(), ast_streamfile(), ast_strlen_zero(), ast_verbose(), ast_waitstream(), ast_channel::cdr, parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, error(), EVENT_FLAG_CALL, ast_bridge_config::features_callee, ast_bridge_config::features_caller, free, LOG_WARNING, manager_event(), parkeduser::next, notify_metermaids(), option_verbose, parkeduser::parkingexten, parkeduser::parkingnum, pbx_builtin_setvar_helper(), S_OR, and VERBOSE_PREFIX_3.
Referenced by load_module().
01819 { 01820 int res = 0; 01821 struct ast_module_user *u; 01822 struct ast_channel *peer=NULL; 01823 struct parkeduser *pu, *pl=NULL; 01824 struct ast_context *con; 01825 01826 int park; 01827 struct ast_bridge_config config; 01828 01829 if (!data) { 01830 ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n"); 01831 return -1; 01832 } 01833 01834 u = ast_module_user_add(chan); 01835 01836 park = atoi((char *)data); 01837 ast_mutex_lock(&parking_lock); 01838 pu = parkinglot; 01839 while(pu) { 01840 if (pu->parkingnum == park) { 01841 if (pl) 01842 pl->next = pu->next; 01843 else 01844 parkinglot = pu->next; 01845 break; 01846 } 01847 pl = pu; 01848 pu = pu->next; 01849 } 01850 ast_mutex_unlock(&parking_lock); 01851 if (pu) { 01852 peer = pu->chan; 01853 con = ast_context_find(parking_con); 01854 if (con) { 01855 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL)) 01856 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 01857 else 01858 notify_metermaids(pu->parkingexten, parking_con); 01859 } else 01860 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 01861 01862 manager_event(EVENT_FLAG_CALL, "UnParkedCall", 01863 "Exten: %s\r\n" 01864 "Channel: %s\r\n" 01865 "From: %s\r\n" 01866 "CallerID: %s\r\n" 01867 "CallerIDName: %s\r\n", 01868 pu->parkingexten, pu->chan->name, chan->name, 01869 S_OR(pu->chan->cid.cid_num, "<unknown>"), 01870 S_OR(pu->chan->cid.cid_name, "<unknown>") 01871 ); 01872 01873 free(pu); 01874 } 01875 /* JK02: it helps to answer the channel if not already up */ 01876 if (chan->_state != AST_STATE_UP) 01877 ast_answer(chan); 01878 01879 if (peer) { 01880 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */ 01881 01882 if (!ast_strlen_zero(courtesytone)) { 01883 int error = 0; 01884 ast_indicate(peer, AST_CONTROL_UNHOLD); 01885 if (parkedplay == 0) { 01886 error = ast_stream_and_wait(chan, courtesytone, chan->language, ""); 01887 } else if (parkedplay == 1) { 01888 error = ast_stream_and_wait(peer, courtesytone, chan->language, ""); 01889 } else if (parkedplay == 2) { 01890 if (!ast_streamfile(chan, courtesytone, chan->language) && 01891 !ast_streamfile(peer, courtesytone, chan->language)) { 01892 /*! \todo XXX we would like to wait on both! */ 01893 res = ast_waitstream(chan, ""); 01894 if (res >= 0) 01895 res = ast_waitstream(peer, ""); 01896 if (res < 0) 01897 error = 1; 01898 } 01899 } 01900 if (error) { 01901 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 01902 ast_hangup(peer); 01903 return -1; 01904 } 01905 } else 01906 ast_indicate(peer, AST_CONTROL_UNHOLD); 01907 01908 res = ast_channel_make_compatible(chan, peer); 01909 if (res < 0) { 01910 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); 01911 ast_hangup(peer); 01912 return -1; 01913 } 01914 /* This runs sorta backwards, since we give the incoming channel control, as if it 01915 were the person called. */ 01916 if (option_verbose > 2) 01917 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park); 01918 01919 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 01920 ast_cdr_setdestchan(chan->cdr, peer->name); 01921 memset(&config, 0, sizeof(struct ast_bridge_config)); 01922 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 01923 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 01924 res = ast_bridge_call(chan, peer, &config); 01925 01926 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 01927 ast_cdr_setdestchan(chan->cdr, peer->name); 01928 01929 /* Simulate the PBX hanging up */ 01930 if (res != AST_PBX_NO_HANGUP_PEER) 01931 ast_hangup(peer); 01932 return res; 01933 } else { 01934 /*! \todo XXX Play a message XXX */ 01935 if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, "")) 01936 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name); 01937 if (option_verbose > 2) 01938 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park); 01939 res = -1; 01940 } 01941 01942 ast_module_user_remove(u); 01943 01944 return res; 01945 }
static void post_manager_event | ( | const char * | s, | |
char * | parkingexten, | |||
struct ast_channel * | chan | |||
) | [static] |
Definition at line 1606 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().
01607 { 01608 manager_event(EVENT_FLAG_CALL, s, 01609 "Exten: %s\r\n" 01610 "Channel: %s\r\n" 01611 "CallerID: %s\r\n" 01612 "CallerIDName: %s\r\n\r\n", 01613 parkingexten, 01614 chan->name, 01615 S_OR(chan->cid.cid_num, "<unknown>"), 01616 S_OR(chan->cid.cid_name, "<unknown>") 01617 ); 01618 }
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 2394 of file res_features.c.
References load_config().
02395 { 02396 return load_config(); 02397 }
static int remap_feature | ( | const char * | name, | |
const char * | value | |||
) | [static] |
Definition at line 1025 of file res_features.c.
References ast_rwlock_unlock(), ast_rwlock_wrlock(), exten, and FEATURES_COUNT.
Referenced by load_config().
01026 { 01027 int x, res = -1; 01028 01029 ast_rwlock_wrlock(&features_lock); 01030 for (x = 0; x < FEATURES_COUNT; x++) { 01031 if (strcasecmp(builtin_features[x].sname, name)) 01032 continue; 01033 01034 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten)); 01035 res = 0; 01036 break; 01037 } 01038 ast_rwlock_unlock(&features_lock); 01039 01040 return res; 01041 }
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(), 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 1103 of file res_features.c.
References AST_BRIDGE_DTMF_CHANNEL_0, AST_BRIDGE_DTMF_CHANNEL_1, ast_clear_flag, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_NEEDSDTMF, AST_FLAGS_ALL, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_set_flag, ast_strdupa, ast_test_flag, ast_call_feature::feature_mask, ast_bridge_config::features_callee, ast_bridge_config::features_caller, FEATURES_COUNT, find_dynamic_feature(), pbx_builtin_getvar_helper(), and strsep().
Referenced by ast_bridge_call().
01104 { 01105 int x; 01106 01107 ast_clear_flag(config, AST_FLAGS_ALL); 01108 01109 ast_rwlock_rdlock(&features_lock); 01110 for (x = 0; x < FEATURES_COUNT; x++) { 01111 if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) 01112 continue; 01113 01114 if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask)) 01115 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 01116 01117 if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask)) 01118 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 01119 } 01120 ast_rwlock_unlock(&features_lock); 01121 01122 if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) { 01123 const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"); 01124 01125 if (dynamic_features) { 01126 char *tmp = ast_strdupa(dynamic_features); 01127 char *tok; 01128 struct ast_call_feature *feature; 01129 01130 /* while we have a feature */ 01131 while ((tok = strsep(&tmp, "#"))) { 01132 AST_LIST_LOCK(&feature_list); 01133 if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) { 01134 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 01135 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); 01136 if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 01137 ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); 01138 } 01139 AST_LIST_UNLOCK(&feature_list); 01140 } 01141 } 01142 } 01143 }
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 2425 of file res_features.c.
References ast_cli_unregister_multiple(), ast_devstate_prov_del(), ast_manager_unregister(), ast_module_user_hangup_all, and ast_unregister_application().
02426 { 02427 ast_module_user_hangup_all(); 02428 02429 ast_manager_unregister("ParkedCalls"); 02430 ast_manager_unregister("Park"); 02431 ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); 02432 ast_unregister_application(parkcall); 02433 ast_devstate_prov_del("Park"); 02434 return ast_unregister_application(parkedcall); 02435 }
static void unmap_features | ( | void | ) | [static] |
Definition at line 1015 of file res_features.c.
References ast_rwlock_unlock(), ast_rwlock_wrlock(), exten, and FEATURES_COUNT.
Referenced by load_config().
01016 { 01017 int x; 01018 01019 ast_rwlock_wrlock(&features_lock); 01020 for (x = 0; x < FEATURES_COUNT; x++) 01021 strcpy(builtin_features[x].exten, builtin_features[x].default_exten); 01022 ast_rwlock_unlock(&features_lock); 01023 }
int adsipark [static] |
Definition at line 98 of file res_features.c.
int atxfernoanswertimeout [static] |
Definition at line 103 of file res_features.c.
struct ast_call_feature builtin_features[] [static] |
Definition at line 882 of file res_features.c.
struct ast_cli_entry cli_features[] [static] |
Definition at line 2021 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 2016 of file res_features.c.
char courtesytone[256] [static] |
Courtesy tone
Definition at line 90 of file res_features.c.
char* descrip [static] |
Initial value:
"ParkedCall(exten):" "Used to connect to a parked call. This application is always\n" "registered internally and does not need to be explicitly added\n" "into the dialplan, although you should include the 'parkedcalls'\n" "context.\n"
Definition at line 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] |
Definition at line 2072 of file res_features.c.
struct ast_app* monitor_app = NULL [static] |
Definition at line 131 of file res_features.c.
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.
char* parkcall = "Park" [static] |
Definition at line 116 of file res_features.c.
char* parkedcall = "ParkedCall" [static] |
Definition at line 78 of file res_features.c.
int parkedplay = 0 [static] |
Who to play the courtesy tone to
Definition at line 91 of file res_features.c.
int parkfindnext [static] |
Definition at line 96 of file res_features.c.
char parking_con[AST_MAX_EXTENSION] [static] |
Context for which parking is made accessible
Definition at line 82 of file res_features.c.
char parking_con_dial[AST_MAX_EXTENSION] [static] |
Context for dialback for parking (KLUDGE)
Definition at line 83 of file res_features.c.
char parking_ext[AST_MAX_EXTENSION] [static] |
Extension you type to park the call
Definition at line 84 of file res_features.c.
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.
int parking_stop [static] |
Last available extension for parking
Definition at line 88 of file res_features.c.
pthread_t parking_thread [static] |
Definition at line 153 of file res_features.c.
struct parkeduser* parkinglot [static] |
Definition at line 149 of file res_features.c.
int parkingtime = DEFAULT_PARK_TIME [static] |
No more than 45 seconds parked before you do something with them
Definition at line 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.
char pickup_ext[AST_MAX_EXTENSION] [static] |
Call pickup extension
Definition at line 85 of file res_features.c.
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 1984 of file res_features.c.
char showparked_help[] [static] |
Initial value:
"Usage: show parkedcalls\n" " Lists currently parked calls.\n"
Definition at line 2012 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] |
Definition at line 100 of file res_features.c.
char xferfailsound[256] [static] |
Call transfer failure sound
Definition at line 93 of file res_features.c.
char xfersound[256] [static] |
Call transfer sound
Definition at line 92 of file res_features.c.