#include "asterisk.h"
#include <pthread.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/options.h"
#include "asterisk/causes.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/app.h"
#include "asterisk/say.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/config.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/utils.h"
#include "asterisk/adsi.h"
#include "asterisk/devicestate.h"
#include "asterisk/monitor.h"
Include dependency graph for res_features.c:
Go to the source code of this file.
Data Structures | |
struct | ast_bridge_thread_obj |
struct | parkeduser |
Defines | |
#define | AST_MAX_WATCHERS 256 |
#define | DEFAULT_FEATURE_DIGIT_TIMEOUT 500 |
#define | DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000 |
#define | DEFAULT_PARK_TIME 45000 |
#define | DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 |
#define | FEATURE_RETURN_HANGUP -1 |
#define | FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER |
#define | FEATURE_RETURN_PASSDIGITS 21 |
#define | FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE |
#define | FEATURE_RETURN_STOREDIGITS 22 |
#define | FEATURE_RETURN_SUCCESS 23 |
#define | FEATURE_RETURN_SUCCESSBREAK 0 |
#define | FEATURE_SENSE_CHAN (1 << 0) |
#define | FEATURE_SENSE_PEER (1 << 1) |
#define | FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0])) |
Enumerations | |
enum | { AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0), AST_FEATURE_FLAG_ONPEER = (1 << 1), AST_FEATURE_FLAG_ONSELF = (1 << 2), AST_FEATURE_FLAG_BYCALLEE = (1 << 3), AST_FEATURE_FLAG_BYCALLER = (1 << 4), AST_FEATURE_FLAG_BYBOTH = (3 << 3) } |
Functions | |
static int | adsi_announce_park (struct ast_channel *chan, char *parkingexten) |
int | ast_bridge_call (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config) |
Bridge a call, optionally allowing redirection. | |
static void * | ast_bridge_call_thread (void *data) |
static void | ast_bridge_call_thread_launch (void *data) |
static int | ast_feature_interpret (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
static struct ast_channel * | ast_feature_request_and_dial (struct ast_channel *caller, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name) |
static | AST_LIST_HEAD_STATIC (feature_list, ast_call_feature) |
int | ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout) |
Park a call via a masqueraded channel. | |
AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS,"Call Features Resource",.load=load_module,.unload=unload_module,.reload=reload,) | |
AST_MUTEX_DEFINE_STATIC (parking_lock) | |
int | ast_park_call (struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout) |
Park a call and read back parked location. | |
char * | ast_parking_ext (void) |
Determine system parking extension Returns the call parking extension for drivers that provide special call parking help. | |
int | ast_pickup_call (struct ast_channel *chan) |
Pickup a call. | |
char * | ast_pickup_ext (void) |
Determine system call pickup extension. | |
void | ast_register_feature (struct ast_call_feature *feature) |
register new feature into feature_set | |
AST_RWLOCK_DEFINE_STATIC (features_lock) | |
void | ast_unregister_feature (struct ast_call_feature *feature) |
unregister feature from feature_set | |
static void | ast_unregister_features (void) |
Remove all features in the list. | |
static int | builtin_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
static int | builtin_automonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
static int | builtin_blindtransfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
static int | builtin_disconnect (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
static int | builtin_parkcall (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
support routing for one touch call parking | |
static int | check_compat (struct ast_channel *c, struct ast_channel *newchan) |
static void | check_goto_on_transfer (struct ast_channel *chan) |
static void * | do_parking_thread (void *ignore) |
Take care of parked calls and unpark them if needed. | |
static int | feature_exec_app (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) |
exec an app by feature | |
static struct ast_call_feature * | find_dynamic_feature (const char *name) |
find a feature by name | |
static int | finishup (struct ast_channel *chan) |
static int | handle_parkedcalls (int fd, int argc, char *argv[]) |
static int | handle_showfeatures (int fd, int argc, char *argv[]) |
static int | load_config (void) |
static int | load_module (void) |
static int | manager_park (struct mansession *s, const struct message *m) |
static int | manager_parking_status (struct mansession *s, const struct message *m) |
Dump lot status. | |
static int | metermaidstate (const char *data) |
metermaids callback from devicestate.c | |
static void | notify_metermaids (char *exten, char *context) |
Notify metermaids that we've changed an extension. | |
static void | park_add_hints (char *context, int start, int stop) |
Add parking hints for all defined parking lots. | |
static int | park_call_exec (struct ast_channel *chan, void *data) |
Park a call. | |
static int | park_exec (struct ast_channel *chan, void *data) |
Pickup parked call. | |
static void | post_manager_event (const char *s, char *parkingexten, struct ast_channel *chan) |
static const char * | real_ctx (struct ast_channel *transferer, struct ast_channel *transferee) |
Find the context for the transfer. | |
static int | reload (void) |
static int | remap_feature (const char *name, const char *value) |
static void | set_c_e_p (struct ast_channel *chan, const char *context, const char *ext, int pri) |
store context, priority and extension | |
static void | set_config_flags (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config) |
static void | set_peers (struct ast_channel **caller, struct ast_channel **callee, struct ast_channel *peer, struct ast_channel *chan, int sense) |
set caller and callee according to the direction | |
static int | unload_module (void) |
static void | unmap_features (void) |
Variables | |
static int | adsipark |
static int | atxfernoanswertimeout |
static struct ast_call_feature | builtin_features [] |
static struct ast_cli_entry | cli_features [] |
static struct ast_cli_entry | cli_show_features_deprecated |
static char | courtesytone [256] |
static char * | descrip |
static char * | descrip2 |
static int | featuredigittimeout |
static char | mandescr_park [] |
static struct ast_app * | monitor_app = NULL |
static int | monitor_ok = 1 |
static int | parkaddhints = 0 |
static char * | parkcall = "Park" |
static char * | parkedcall = "ParkedCall" |
static int | parkedplay = 0 |
static int | parkfindnext |
static char | parking_con [AST_MAX_EXTENSION] |
static char | parking_con_dial [AST_MAX_EXTENSION] |
static char | parking_ext [AST_MAX_EXTENSION] |
static int | parking_offset |
static int | parking_start |
static int | parking_stop |
static pthread_t | parking_thread |
static struct parkeduser * | parkinglot |
static int | parkingtime = DEFAULT_PARK_TIME |
static char | parkmohclass [MAX_MUSICCLASS] |
static char | pickup_ext [AST_MAX_EXTENSION] |
static char * | registrar = "res_features" |
static char | showfeatures_help [] |
static char | showparked_help [] |
static char * | synopsis = "Answer a parked call" |
static char * | synopsis2 = "Park yourself" |
static int | transferdigittimeout |
static char | xferfailsound [256] |
static char | xfersound [256] |
Definition in file res_features.c.
#define AST_MAX_WATCHERS 256 |
Definition at line 67 of file res_features.c.
#define DEFAULT_FEATURE_DIGIT_TIMEOUT 500 |
#define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000 |
#define DEFAULT_PARK_TIME 45000 |
Definition at line 62 of file res_features.c.
#define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 |
#define FEATURE_RETURN_HANGUP -1 |
#define FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER |
#define FEATURE_RETURN_PASSDIGITS 21 |
Definition at line 473 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 475 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 477 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 880 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_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_OPTION, AST_CONTROL_RINGING, 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_log(), AST_OPTION_FLAG_REQUEST, ast_strdupa, ast_strlen_zero(), ast_channel::cdr, ast_cdr::channel, config, ast_option_header::data, ast_channel::data, ast_cdr::dstchannel, f, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_option_header::flag, free, LOG_DEBUG, LOG_WARNING, monitor_app, ast_option_header::option, option_debug, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), set_config_flags(), and ast_cdr::userfield.
Referenced by app_exec(), ast_bridge_call_thread(), builtin_atxfer(), park_exec(), and try_calling().
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 if (f->subclass == AST_CONTROL_RINGING) 01470 ast_indicate(other, AST_CONTROL_RINGING); 01471 else if (f->subclass == -1) 01472 ast_indicate(other, -1); 01473 else if (f->subclass == AST_CONTROL_FLASH) 01474 ast_indicate(other, AST_CONTROL_FLASH); 01475 else if (f->subclass == AST_CONTROL_OPTION) { 01476 aoh = f->data; 01477 /* Forward option Requests */ 01478 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) 01479 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0); 01480 } 01481 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 01482 /* eat it */ 01483 } else if (f->frametype == AST_FRAME_DTMF) { 01484 char *featurecode; 01485 int sense; 01486 01487 hadfeatures = hasfeatures; 01488 /* This cannot overrun because the longest feature is one shorter than our buffer */ 01489 if (who == chan) { 01490 sense = FEATURE_SENSE_CHAN; 01491 featurecode = chan_featurecode; 01492 } else { 01493 sense = FEATURE_SENSE_PEER; 01494 featurecode = peer_featurecode; 01495 } 01496 /*! append the event to featurecode. we rely on the string being zero-filled, and 01497 * not overflowing it. 01498 * \todo XXX how do we guarantee the latter ? 01499 */ 01500 featurecode[strlen(featurecode)] = f->subclass; 01501 /* Get rid of the frame before we start doing "stuff" with the channels */ 01502 ast_frfree(f); 01503 f = NULL; 01504 config->feature_timer = backup_config.feature_timer; 01505 res = ast_feature_interpret(chan, peer, config, featurecode, sense); 01506 switch(res) { 01507 case FEATURE_RETURN_PASSDIGITS: 01508 ast_dtmf_stream(other, who, featurecode, 0); 01509 /* Fall through */ 01510 case FEATURE_RETURN_SUCCESS: 01511 memset(featurecode, 0, sizeof(chan_featurecode)); 01512 break; 01513 } 01514 if (res >= FEATURE_RETURN_PASSDIGITS) { 01515 res = 0; 01516 } else 01517 break; 01518 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 01519 if (hadfeatures && !hasfeatures) { 01520 /* Restore backup */ 01521 memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); 01522 memset(&backup_config, 0, sizeof(struct ast_bridge_config)); 01523 } else if (hasfeatures) { 01524 if (!hadfeatures) { 01525 /* Backup configuration */ 01526 memcpy(&backup_config, config, sizeof(struct ast_bridge_config)); 01527 /* Setup temporary config options */ 01528 config->play_warning = 0; 01529 ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 01530 ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 01531 config->warning_freq = 0; 01532 config->warning_sound = NULL; 01533 config->end_sound = NULL; 01534 config->start_sound = NULL; 01535 config->firstpass = 0; 01536 } 01537 config->start_time = ast_tvnow(); 01538 config->feature_timer = featuredigittimeout; 01539 if (option_debug) 01540 ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer); 01541 } 01542 } 01543 if (f) 01544 ast_frfree(f); 01545 01546 } 01547 01548 /* arrange the cdrs */ 01549 bridge_cdr = ast_cdr_alloc(); 01550 if (bridge_cdr) { 01551 if (chan->cdr && peer->cdr) { /* both of them? merge */ 01552 ast_cdr_init(bridge_cdr,chan); /* seems more logicaller to use the destination as a base, but, really, it's random */ 01553 ast_cdr_start(bridge_cdr); /* now is the time to start */ 01554 01555 /* absorb the channel cdr */ 01556 ast_cdr_merge(bridge_cdr, chan->cdr); 01557 ast_cdr_discard(chan->cdr); /* no posting these guys */ 01558 01559 /* absorb the peer cdr */ 01560 ast_cdr_merge(bridge_cdr, peer->cdr); 01561 ast_cdr_discard(peer->cdr); /* no posting these guys */ 01562 peer->cdr = NULL; 01563 chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */ 01564 } else if (chan->cdr) { 01565 /* take the cdr from the channel - literally */ 01566 ast_cdr_init(bridge_cdr,chan); 01567 /* absorb this data */ 01568 ast_cdr_merge(bridge_cdr, chan->cdr); 01569 ast_cdr_discard(chan->cdr); /* no posting these guys */ 01570 chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */ 01571 } else if (peer->cdr) { 01572 /* take the cdr from the peer - literally */ 01573 ast_cdr_init(bridge_cdr,peer); 01574 /* absorb this data */ 01575 ast_cdr_merge(bridge_cdr, peer->cdr); 01576 ast_cdr_discard(peer->cdr); /* no posting these guys */ 01577 peer->cdr = NULL; 01578 peer->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */ 01579 } else { 01580 /* make up a new cdr */ 01581 ast_cdr_init(bridge_cdr,chan); /* eh, just pick one of them */ 01582 chan->cdr = bridge_cdr; /* */ 01583 } 01584 if (ast_strlen_zero(bridge_cdr->dstchannel)) { 01585 if (strcmp(bridge_cdr->channel, peer->name) != 0) 01586 ast_cdr_setdestchan(bridge_cdr, peer->name); 01587 else 01588 ast_cdr_setdestchan(bridge_cdr, chan->name); 01589 } 01590 } 01591 return res; 01592 }
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 1045 of file res_features.c.
References ast_copy_flags, AST_FLAGS_ALL, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verbose(), builtin_features, config, ast_call_feature::exten, exten, ast_call_feature::feature_mask, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_STOREDIGITS, FEATURE_SENSE_CHAN, FEATURES_COUNT, find_dynamic_feature(), ast_channel::flags, LOG_DEBUG, ast_call_feature::operation, option_debug, option_verbose, pbx_builtin_getvar_helper(), ast_call_feature::sname, strsep(), and VERBOSE_PREFIX_3.
Referenced by ast_bridge_call().
01046 { 01047 int x; 01048 struct ast_flags features; 01049 int res = FEATURE_RETURN_PASSDIGITS; 01050 struct ast_call_feature *feature; 01051 const char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES"); 01052 char *tmp, *tok; 01053 01054 if (sense == FEATURE_SENSE_CHAN) 01055 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL); 01056 else 01057 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL); 01058 if (option_debug > 2) 01059 ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags); 01060 01061 ast_rwlock_rdlock(&features_lock); 01062 for (x = 0; x < FEATURES_COUNT; x++) { 01063 if ((ast_test_flag(&features, builtin_features[x].feature_mask)) && 01064 !ast_strlen_zero(builtin_features[x].exten)) { 01065 /* Feature is up for consideration */ 01066 if (!strcmp(builtin_features[x].exten, code)) { 01067 res = builtin_features[x].operation(chan, peer, config, code, sense); 01068 break; 01069 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) { 01070 if (res == FEATURE_RETURN_PASSDIGITS) 01071 res = FEATURE_RETURN_STOREDIGITS; 01072 } 01073 } 01074 } 01075 ast_rwlock_unlock(&features_lock); 01076 01077 if (ast_strlen_zero(dynamic_features)) 01078 return res; 01079 01080 tmp = ast_strdupa(dynamic_features); 01081 01082 while ((tok = strsep(&tmp, "#"))) { 01083 AST_LIST_LOCK(&feature_list); 01084 if (!(feature = find_dynamic_feature(tok))) 01085 continue; 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] |
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(), builtin_features, ast_channel::cdr, ast_call_feature::exten, f, FEATURES_COUNT, ast_channel::hangupcause, len, LOG_NOTICE, LOG_WARNING, option_verbose, pbx_builtin_setvar_helper(), and VERBOSE_PREFIX_3.
Referenced by builtin_atxfer().
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 440 of file res_features.c.
References ast_channel::amaflags, ast_channel_alloc(), ast_channel_masquerade(), ast_frfree(), ast_log(), ast_park_call(), ast_read(), AST_STATE_DOWN, ast_channel::context, ast_channel::exten, f, LOG_WARNING, ast_channel::priority, ast_channel::readformat, set_c_e_p(), and ast_channel::writeformat.
Referenced by manager_park(), mgcp_ss(), parkandannounce_exec(), rpt_exec(), and ss_thread().
00441 { 00442 struct ast_channel *chan; 00443 struct ast_frame *f; 00444 00445 /* Make a new, fake channel that we'll use to masquerade in the real one */ 00446 if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) { 00447 ast_log(LOG_WARNING, "Unable to create parked channel\n"); 00448 return -1; 00449 } 00450 00451 /* Make formats okay */ 00452 chan->readformat = rchan->readformat; 00453 chan->writeformat = rchan->writeformat; 00454 ast_channel_masquerade(chan, rchan); 00455 00456 /* Setup the extensions and such */ 00457 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority); 00458 00459 /* Make the masq execute */ 00460 f = ast_read(chan); 00461 if (f) 00462 ast_frfree(f); 00463 00464 ast_park_call(chan, peer, timeout, extout); 00465 return 0; 00466 }
AST_MODULE_INFO | ( | ASTERISK_GPL_KEY | , | |
AST_MODFLAG_GLOBAL_SYMBOLS | , | |||
"Call Features Resource" | , | |||
. | load = load_module , |
|||
. | unload = unload_module , |
|||
. | reload = reload | |||
) |
AST_MUTEX_DEFINE_STATIC | ( | parking_lock | ) |
protects all static variables above
int ast_park_call | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
int | timeout, | |||
int * | extout | |||
) |
Park a call and read back parked location.
Definition at line 311 of file res_features.c.
References adsi_announce_park(), ast_channel::appl, ast_add_extension2(), ast_adsi_available(), ast_adsi_unload_session(), ast_calloc, ast_context_create(), ast_context_find(), AST_CONTROL_HOLD, ast_exists_extension(), ast_free, ast_indicate_data(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_say_digits(), ast_strlen_zero(), ast_verbose(), ast_channel::context, ast_channel::data, EVENT_FLAG_CALL, ast_channel::exten, free, LOG_ERROR, LOG_WARNING, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, manager_event(), parkeduser::next, notify_metermaids(), parkeduser::notquiteyet, option_verbose, parkinglot, parkeduser::parkingnum, pbx_builtin_getvar_helper(), ast_channel::priority, S_OR, strdup, and VERBOSE_PREFIX_2.
Referenced by ast_masq_park_call(), builtin_blindtransfer(), builtin_parkcall(), iax_park_thread(), park_call_exec(), and sip_park_thread().
00312 { 00313 struct parkeduser *pu, *cur; 00314 int i, x = -1, parking_range; 00315 struct ast_context *con; 00316 const char *parkingexten; 00317 00318 /* Allocate memory for parking data */ 00319 if (!(pu = ast_calloc(1, sizeof(*pu)))) 00320 return -1; 00321 00322 /* Lock parking lot */ 00323 ast_mutex_lock(&parking_lock); 00324 /* Check for channel variable PARKINGEXTEN */ 00325 parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN"); 00326 if (!ast_strlen_zero(parkingexten)) { 00327 if (ast_exists_extension(NULL, parking_con, parkingexten, 1, NULL)) { 00328 ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con); 00329 return 0; /* Continue execution if possible */ 00330 } 00331 ast_copy_string(pu->parkingexten, parkingexten, sizeof(pu->parkingexten)); 00332 x = atoi(parkingexten); 00333 } else { 00334 /* Select parking space within range */ 00335 parking_range = parking_stop - parking_start+1; 00336 for (i = 0; i < parking_range; i++) { 00337 x = (i + parking_offset) % parking_range + parking_start; 00338 cur = parkinglot; 00339 while(cur) { 00340 if (cur->parkingnum == x) 00341 break; 00342 cur = cur->next; 00343 } 00344 if (!cur) 00345 break; 00346 } 00347 00348 if (!(i < parking_range)) { 00349 ast_log(LOG_WARNING, "No more parking spaces\n"); 00350 free(pu); 00351 ast_mutex_unlock(&parking_lock); 00352 return -1; 00353 } 00354 /* Set pointer for next parking */ 00355 if (parkfindnext) 00356 parking_offset = x - parking_start + 1; 00357 } 00358 00359 chan->appl = "Parked Call"; 00360 chan->data = NULL; 00361 00362 pu->chan = chan; 00363 00364 /* Put the parked channel on hold if we have two different channels */ 00365 if (chan != peer) { 00366 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 00367 S_OR(parkmohclass, NULL), 00368 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 00369 } 00370 00371 pu->start = ast_tvnow(); 00372 pu->parkingnum = x; 00373 pu->parkingtime = (timeout > 0) ? timeout : parkingtime; 00374 if (extout) 00375 *extout = x; 00376 00377 if (peer) 00378 ast_copy_string(pu->peername, peer->name, sizeof(pu->peername)); 00379 00380 /* Remember what had been dialed, so that if the parking 00381 expires, we try to come back to the same place */ 00382 ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context)); 00383 ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten)); 00384 pu->priority = chan->macropriority ? chan->macropriority : chan->priority; 00385 pu->next = parkinglot; 00386 parkinglot = pu; 00387 00388 /* If parking a channel directly, don't quiet yet get parking running on it */ 00389 if (peer == chan) 00390 pu->notquiteyet = 1; 00391 ast_mutex_unlock(&parking_lock); 00392 /* Wake up the (presumably select()ing) thread */ 00393 pthread_kill(parking_thread, SIGURG); 00394 if (option_verbose > 1) 00395 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)); 00396 00397 if (pu->parkingnum != -1) 00398 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x); 00399 manager_event(EVENT_FLAG_CALL, "ParkedCall", 00400 "Exten: %s\r\n" 00401 "Channel: %s\r\n" 00402 "From: %s\r\n" 00403 "Timeout: %ld\r\n" 00404 "CallerID: %s\r\n" 00405 "CallerIDName: %s\r\n", 00406 pu->parkingexten, pu->chan->name, peer ? peer->name : "", 00407 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL), 00408 S_OR(pu->chan->cid.cid_num, "<unknown>"), 00409 S_OR(pu->chan->cid.cid_name, "<unknown>") 00410 ); 00411 00412 if (peer && adsipark && ast_adsi_available(peer)) { 00413 adsi_announce_park(peer, pu->parkingexten); /* Only supports parking numbers */ 00414 ast_adsi_unload_session(peer); 00415 } 00416 00417 con = ast_context_find(parking_con); 00418 if (!con) 00419 con = ast_context_create(NULL, parking_con, registrar); 00420 if (!con) /* Still no context? Bad */ 00421 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); 00422 else { /* Add extension to context */ 00423 if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), ast_free, registrar)) 00424 notify_metermaids(pu->parkingexten, parking_con); 00425 } 00426 /* Tell the peer channel the number of the parking space */ 00427 if (peer && pu->parkingnum != -1) /* Only say number if it's a number */ 00428 ast_say_digits(peer, pu->parkingnum, "", peer->language); 00429 if (pu->notquiteyet) { 00430 /* Wake up parking thread if we're really done */ 00431 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 00432 S_OR(parkmohclass, NULL), 00433 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 00434 pu->notquiteyet = 0; 00435 pthread_kill(parking_thread, SIGURG); 00436 } 00437 return 0; 00438 }
char* ast_parking_ext | ( | void | ) |
Determine system parking extension Returns the call parking extension for drivers that provide special call parking help.
Definition at line 155 of file res_features.c.
Referenced by builtin_blindtransfer(), dp_lookup(), handle_request_refer(), mgcp_ss(), socket_process(), and ss_thread().
00156 { 00157 return parking_ext; 00158 }
int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
Definition at line 2122 of file res_features.c.
References ast_channel::_state, ast_answer(), ast_channel_masquerade(), ast_channel_unlock, ast_channel_walk_locked(), AST_CONTROL_ANSWER, ast_log(), ast_queue_control(), AST_STATE_RING, AST_STATE_RINGING, ast_channel::callgroup, LOG_DEBUG, LOG_WARNING, option_debug, ast_channel::pbx, and ast_channel::pickupgroup.
Referenced by cb_events(), handle_request_invite(), mgcp_ss(), and ss_thread().
02123 { 02124 struct ast_channel *cur = NULL; 02125 int res = -1; 02126 02127 while ( (cur = ast_channel_walk_locked(cur)) != NULL) { 02128 if (!cur->pbx && 02129 (cur != chan) && 02130 (chan->pickupgroup & cur->callgroup) && 02131 ((cur->_state == AST_STATE_RINGING) || 02132 (cur->_state == AST_STATE_RING))) { 02133 break; 02134 } 02135 ast_channel_unlock(cur); 02136 } 02137 if (cur) { 02138 if (option_debug) 02139 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name); 02140 res = ast_answer(chan); 02141 if (res) 02142 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); 02143 res = ast_queue_control(chan, AST_CONTROL_ANSWER); 02144 if (res) 02145 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); 02146 res = ast_channel_masquerade(cur, chan); 02147 if (res) 02148 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */ 02149 ast_channel_unlock(cur); 02150 } else { 02151 if (option_debug) 02152 ast_log(LOG_DEBUG, "No call pickup possible...\n"); 02153 } 02154 return res; 02155 }
char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 160 of file res_features.c.
Referenced by cb_events(), get_destination(), handle_request_invite(), handle_showfeatures(), mgcp_ss(), and ss_thread().
00161 { 00162 return pickup_ext; 00163 }
void ast_register_feature | ( | struct ast_call_feature * | feature | ) |
register new feature into feature_set
feature | an ast_call_feature object which contains a keysequence and a callback function which is called when this keysequence is pressed during a call. |
Definition at line 897 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.
00898 { 00899 if (!feature) { 00900 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 00901 return; 00902 } 00903 00904 AST_LIST_LOCK(&feature_list); 00905 AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry); 00906 AST_LIST_UNLOCK(&feature_list); 00907 00908 if (option_verbose >= 2) 00909 ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname); 00910 }
AST_RWLOCK_DEFINE_STATIC | ( | features_lock | ) |
void ast_unregister_feature | ( | struct ast_call_feature * | feature | ) |
unregister feature from feature_set
feature | the ast_call_feature object which was registered before |
Definition at line 913 of file res_features.c.
References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free.
00914 { 00915 if (!feature) 00916 return; 00917 00918 AST_LIST_LOCK(&feature_list); 00919 AST_LIST_REMOVE(&feature_list,feature,feature_entry); 00920 AST_LIST_UNLOCK(&feature_list); 00921 free(feature); 00922 }
static void ast_unregister_features | ( | void | ) | [static] |
Remove all features in the list.
Definition at line 925 of file res_features.c.
References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and free.
00926 { 00927 struct ast_call_feature *feature; 00928 00929 AST_LIST_LOCK(&feature_list); 00930 while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry))) 00931 free(feature); 00932 AST_LIST_UNLOCK(&feature_list); 00933 }
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 743 of file res_features.c.
References ast_channel::_softhangup, ast_channel::_state, ast_app_dtget(), ast_autoservice_start(), ast_autoservice_stop(), ast_best_codec(), ast_bridge_call(), ast_bridge_call_thread_launch(), ast_calloc, ast_channel_alloc(), ast_channel_masquerade(), ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, AST_DIGIT_ANY, ast_exists_extension(), ast_explicit_goto(), AST_FEATURE_DISCONNECT, ast_feature_request_and_dial(), AST_FLAGS_ALL, ast_frfree(), ast_hangup(), ast_indicate(), ast_log(), ast_read(), ast_set_flag, AST_STATE_DOWN, AST_STATE_UP, ast_stream_and_wait(), ast_waitfordigit(), ast_bridge_thread_obj::bconfig, ast_bridge_thread_obj::chan, check_compat(), ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, config, ast_channel::context, ast_channel::exten, f, FEATURE_RETURN_SUCCESS, ast_bridge_config::features_callee, ast_bridge_config::features_caller, finishup(), LOG_DEBUG, LOG_WARNING, ast_channel::nativeformats, option_debug, ast_bridge_thread_obj::peer, ast_channel::priority, ast_channel::readformat, real_ctx(), set_peers(), and ast_channel::writeformat.
00744 { 00745 struct ast_channel *transferer; 00746 struct ast_channel *transferee; 00747 const char *transferer_real_context; 00748 char xferto[256] = ""; 00749 int res; 00750 int outstate=0; 00751 struct ast_channel *newchan; 00752 struct ast_channel *xferchan; 00753 struct ast_bridge_thread_obj *tobj; 00754 struct ast_bridge_config bconfig; 00755 struct ast_frame *f; 00756 int l; 00757 00758 if (option_debug) 00759 ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense); 00760 set_peers(&transferer, &transferee, peer, chan, sense); 00761 transferer_real_context = real_ctx(transferer, transferee); 00762 /* Start autoservice on chan while we talk to the originator */ 00763 ast_autoservice_start(transferee); 00764 ast_indicate(transferee, AST_CONTROL_HOLD); 00765 00766 /* Transfer */ 00767 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY); 00768 if (res < 0) { 00769 finishup(transferee); 00770 return res; 00771 } 00772 if (res > 0) /* If they've typed a digit already, handle it */ 00773 xferto[0] = (char) res; 00774 00775 /* this is specific of atxfer */ 00776 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 00777 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */ 00778 finishup(transferee); 00779 return res; 00780 } 00781 if (res == 0) { 00782 ast_log(LOG_WARNING, "Did not read data.\n"); 00783 finishup(transferee); 00784 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, "")) 00785 return -1; 00786 return FEATURE_RETURN_SUCCESS; 00787 } 00788 00789 /* valid extension, res == 1 */ 00790 if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) { 00791 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context); 00792 finishup(transferee); 00793 if (ast_stream_and_wait(transferer, "beeperr", transferer->language, "")) 00794 return -1; 00795 return FEATURE_RETURN_SUCCESS; 00796 } 00797 00798 l = strlen(xferto); 00799 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); /* append context */ 00800 newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats), 00801 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name); 00802 ast_indicate(transferer, -1); 00803 if (!newchan) { 00804 finishup(transferee); 00805 /* any reason besides user requested cancel and busy triggers the failed sound */ 00806 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY && 00807 ast_stream_and_wait(transferer, xferfailsound, transferer->language, "")) 00808 return -1; 00809 return FEATURE_RETURN_SUCCESS; 00810 } 00811 00812 if (check_compat(transferer, newchan)) 00813 return -1; 00814 memset(&bconfig,0,sizeof(struct ast_bridge_config)); 00815 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 00816 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 00817 res = ast_bridge_call(transferer, newchan, &bconfig); 00818 if (newchan->_softhangup || !transferer->_softhangup) { 00819 ast_hangup(newchan); 00820 if (ast_stream_and_wait(transferer, xfersound, transferer->language, "")) 00821 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 00822 finishup(transferee); 00823 transferer->_softhangup = 0; 00824 return FEATURE_RETURN_SUCCESS; 00825 } 00826 00827 if (check_compat(transferee, newchan)) 00828 return -1; 00829 00830 ast_indicate(transferee, AST_CONTROL_UNHOLD); 00831 00832 if ((ast_autoservice_stop(transferee) < 0) 00833 || (ast_waitfordigit(transferee, 100) < 0) 00834 || (ast_waitfordigit(newchan, 100) < 0) 00835 || ast_check_hangup(transferee) 00836 || ast_check_hangup(newchan)) { 00837 ast_hangup(newchan); 00838 return -1; 00839 } 00840 00841 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name); 00842 if (!xferchan) { 00843 ast_hangup(newchan); 00844 return -1; 00845 } 00846 /* Make formats okay */ 00847 xferchan->readformat = transferee->readformat; 00848 xferchan->writeformat = transferee->writeformat; 00849 ast_channel_masquerade(xferchan, transferee); 00850 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority); 00851 xferchan->_state = AST_STATE_UP; 00852 ast_clear_flag(xferchan, AST_FLAGS_ALL); 00853 xferchan->_softhangup = 0; 00854 00855 if ((f = ast_read(xferchan))) 00856 ast_frfree(f); 00857 00858 newchan->_state = AST_STATE_UP; 00859 ast_clear_flag(newchan, AST_FLAGS_ALL); 00860 newchan->_softhangup = 0; 00861 00862 tobj = ast_calloc(1, sizeof(struct ast_bridge_thread_obj)); 00863 if (!tobj) { 00864 ast_hangup(xferchan); 00865 ast_hangup(newchan); 00866 return -1; 00867 } 00868 tobj->chan = xferchan; 00869 tobj->peer = newchan; 00870 tobj->bconfig = *config; 00871 00872 if (ast_stream_and_wait(newchan, xfersound, newchan->language, "")) 00873 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 00874 ast_bridge_call_thread_launch(tobj); 00875 return -1; /* XXX meaning the channel is bridged ? */ 00876 }
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 529 of file res_features.c.
References ast_autoservice_start(), ast_autoservice_stop(), ast_log(), ast_monitor_stop(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_verbose(), ast_channel::cid, ast_callerid::cid_num, FEATURE_RETURN_SUCCESS, len, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_channel::monitor, monitor_app, option_verbose, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), S_OR, set_peers(), and VERBOSE_PREFIX_3.
00530 { 00531 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 00532 int x = 0; 00533 size_t len; 00534 struct ast_channel *caller_chan, *callee_chan; 00535 00536 if (!monitor_ok) { 00537 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 00538 return -1; 00539 } 00540 00541 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) { 00542 monitor_ok = 0; 00543 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 00544 return -1; 00545 } 00546 00547 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 00548 00549 if (!ast_strlen_zero(courtesytone)) { 00550 if (ast_autoservice_start(callee_chan)) 00551 return -1; 00552 if (ast_stream_and_wait(caller_chan, courtesytone, caller_chan->language, "")) { 00553 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 00554 ast_autoservice_stop(callee_chan); 00555 return -1; 00556 } 00557 if (ast_autoservice_stop(callee_chan)) 00558 return -1; 00559 } 00560 00561 if (callee_chan->monitor) { 00562 if (option_verbose > 3) 00563 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code); 00564 ast_monitor_stop(callee_chan, 1); 00565 return FEATURE_RETURN_SUCCESS; 00566 } 00567 00568 if (caller_chan && callee_chan) { 00569 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT"); 00570 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR"); 00571 00572 if (!touch_format) 00573 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT"); 00574 00575 if (!touch_monitor) 00576 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR"); 00577 00578 if (touch_monitor) { 00579 len = strlen(touch_monitor) + 50; 00580 args = alloca(len); 00581 touch_filename = alloca(len); 00582 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor); 00583 snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename); 00584 } else { 00585 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name)); 00586 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name)); 00587 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 00588 args = alloca(len); 00589 touch_filename = alloca(len); 00590 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id); 00591 snprintf(args, len, "%s|%s|m", S_OR(touch_format, "wav"), touch_filename); 00592 } 00593 00594 for( x = 0; x < strlen(args); x++) { 00595 if (args[x] == '/') 00596 args[x] = '-'; 00597 } 00598 00599 if (option_verbose > 3) 00600 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args); 00601 00602 pbx_exec(callee_chan, monitor_app, args); 00603 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 00604 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 00605 00606 return FEATURE_RETURN_SUCCESS; 00607 } 00608 00609 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); 00610 return -1; 00611 }
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 640 of file res_features.c.
References ast_app_dtget(), ast_async_goto(), ast_autoservice_start(), ast_cdr_alloc(), ast_cdr_init(), ast_cdr_setapp(), ast_cdr_setdestchan(), ast_cdr_start(), AST_CONTROL_HOLD, AST_DIGIT_ANY, ast_exists_extension(), ast_indicate(), ast_log(), ast_park_call(), ast_parking_ext(), AST_PBX_KEEPALIVE, AST_PBX_NO_HANGUP_PEER, ast_stopstream(), ast_stream_and_wait(), ast_verbose(), check_goto_on_transfer(), ast_channel::cid, ast_callerid::cid_num, FEATURE_RETURN_SUCCESS, finishup(), LOG_WARNING, option_verbose, ast_channel::pbx, pbx_builtin_setvar_helper(), real_ctx(), set_c_e_p(), set_peers(), VERBOSE_PREFIX_2, and VERBOSE_PREFIX_3.
00641 { 00642 struct ast_channel *transferer; 00643 struct ast_channel *transferee; 00644 const char *transferer_real_context; 00645 char xferto[256]; 00646 int res; 00647 00648 set_peers(&transferer, &transferee, peer, chan, sense); 00649 transferer_real_context = real_ctx(transferer, transferee); 00650 /* Start autoservice on chan while we talk to the originator */ 00651 ast_autoservice_start(transferee); 00652 ast_indicate(transferee, AST_CONTROL_HOLD); 00653 00654 memset(xferto, 0, sizeof(xferto)); 00655 00656 /* Transfer */ 00657 res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY); 00658 if (res < 0) { 00659 finishup(transferee); 00660 return -1; /* error ? */ 00661 } 00662 if (res > 0) /* If they've typed a digit already, handle it */ 00663 xferto[0] = (char) res; 00664 00665 ast_stopstream(transferer); 00666 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 00667 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */ 00668 finishup(transferee); 00669 return res; 00670 } 00671 if (!strcmp(xferto, ast_parking_ext())) { 00672 res = finishup(transferee); 00673 if (res) 00674 res = -1; 00675 else if (!ast_park_call(transferee, transferer, 0, NULL)) { /* success */ 00676 /* We return non-zero, but tell the PBX not to hang the channel when 00677 the thread dies -- We have to be careful now though. We are responsible for 00678 hanging up the channel, else it will never be hung up! */ 00679 00680 return (transferer == peer) ? AST_PBX_KEEPALIVE : AST_PBX_NO_HANGUP_PEER; 00681 } else { 00682 ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name); 00683 } 00684 /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */ 00685 } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) { 00686 pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", transferee->name); 00687 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name); 00688 res=finishup(transferee); 00689 if (!transferer->cdr) { 00690 transferer->cdr=ast_cdr_alloc(); 00691 if (transferer) { 00692 ast_cdr_init(transferer->cdr, transferer); /* initilize our channel's cdr */ 00693 ast_cdr_start(transferer->cdr); 00694 } 00695 } 00696 if (transferer->cdr) { 00697 ast_cdr_setdestchan(transferer->cdr, transferee->name); 00698 ast_cdr_setapp(transferer->cdr, "BLINDTRANSFER",""); 00699 } 00700 if (!transferee->pbx) { 00701 /* Doh! Use our handy async_goto functions */ 00702 if (option_verbose > 2) 00703 ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n" 00704 ,transferee->name, xferto, transferer_real_context); 00705 if (ast_async_goto(transferee, transferer_real_context, xferto, 1)) 00706 ast_log(LOG_WARNING, "Async goto failed :-(\n"); 00707 res = -1; 00708 } else { 00709 /* Set the channel's new extension, since it exists, using transferer context */ 00710 set_c_e_p(transferee, transferer_real_context, xferto, 0); 00711 } 00712 check_goto_on_transfer(transferer); 00713 return res; 00714 } else { 00715 if (option_verbose > 2) 00716 ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context); 00717 } 00718 if (ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0 ) { 00719 finishup(transferee); 00720 return -1; 00721 } 00722 ast_stopstream(transferer); 00723 res = finishup(transferee); 00724 if (res) { 00725 if (option_verbose > 1) 00726 ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name); 00727 return res; 00728 } 00729 return FEATURE_RETURN_SUCCESS; 00730 }
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 613 of file res_features.c.
References ast_verbose(), FEATURE_RETURN_HANGUP, option_verbose, and VERBOSE_PREFIX_3.
00614 { 00615 if (option_verbose > 3) 00616 ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code); 00617 return FEATURE_RETURN_HANGUP; 00618 }
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 496 of file res_features.c.
References ast_channel::_state, ast_answer(), ast_module_user_add, ast_module_user_remove, ast_park_call(), AST_PBX_KEEPALIVE, AST_PBX_NO_HANGUP_PEER, ast_safe_sleep(), AST_STATE_UP, ast_module_user::chan, ast_channel::exten, FEATURE_SENSE_CHAN, ast_channel::priority, and set_peers().
00497 { 00498 struct ast_channel *parker; 00499 struct ast_channel *parkee; 00500 int res = 0; 00501 struct ast_module_user *u; 00502 00503 u = ast_module_user_add(chan); 00504 00505 set_peers(&parker, &parkee, peer, chan, sense); 00506 /* Setup the exten/priority to be s/1 since we don't know 00507 where this call should return */ 00508 strcpy(chan->exten, "s"); 00509 chan->priority = 1; 00510 if (chan->_state != AST_STATE_UP) 00511 res = ast_answer(chan); 00512 if (!res) 00513 res = ast_safe_sleep(chan, 1000); 00514 if (!res) 00515 res = ast_park_call(parkee, parker, 0, NULL); 00516 00517 ast_module_user_remove(u); 00518 00519 if (!res) { 00520 if (sense == FEATURE_SENSE_CHAN) 00521 res = AST_PBX_NO_HANGUP_PEER; 00522 else 00523 res = AST_PBX_KEEPALIVE; 00524 } 00525 return res; 00526 00527 }
static int check_compat | ( | struct ast_channel * | c, | |
struct ast_channel * | newchan | |||
) | [static] |
Definition at line 732 of file res_features.c.
References ast_channel_make_compatible(), ast_hangup(), ast_log(), and LOG_WARNING.
Referenced by builtin_atxfer().
00733 { 00734 if (ast_channel_make_compatible(c, newchan) < 0) { 00735 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", 00736 c->name, newchan->name); 00737 ast_hangup(newchan); 00738 return -1; 00739 } 00740 return 0; 00741 }
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 1609 of file res_features.c.
References ast_add_extension2(), ast_clear_flag, ast_context_create(), ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, ast_free, ast_frfree(), ast_hangup(), ast_indicate(), ast_indicate_data(), ast_log(), AST_MAX_EXTENSION, AST_MAX_FDS, ast_mutex_lock(), ast_mutex_unlock(), ast_pbx_start(), ast_read(), ast_select(), ast_set_flag, ast_strdupa, ast_strlen_zero(), ast_verbose(), parkeduser::chan, ast_channel::context, parkeduser::context, ast_channel::exten, parkeduser::exten, f, ast_channel::fds, free, LOG_DEBUG, LOG_ERROR, LOG_WARNING, parkeduser::moh_trys, parkeduser::next, notify_metermaids(), parkeduser::notquiteyet, option_debug, option_verbose, parkeduser::parkingexten, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, post_manager_event(), ast_channel::priority, parkeduser::priority, S_OR, set_c_e_p(), parkeduser::start, strdup, and VERBOSE_PREFIX_2.
Referenced by load_module().
01610 { 01611 fd_set rfds, efds; /* results from previous select, to be preserved across loops. */ 01612 FD_ZERO(&rfds); 01613 FD_ZERO(&efds); 01614 01615 for (;;) { 01616 struct parkeduser *pu, *pl, *pt = NULL; 01617 int ms = -1; /* select timeout, uninitialized */ 01618 int max = -1; /* max fd, none there yet */ 01619 fd_set nrfds, nefds; /* args for the next select */ 01620 FD_ZERO(&nrfds); 01621 FD_ZERO(&nefds); 01622 01623 ast_mutex_lock(&parking_lock); 01624 pl = NULL; 01625 pu = parkinglot; 01626 /* navigate the list with prev-cur pointers to support removals */ 01627 while (pu) { 01628 struct ast_channel *chan = pu->chan; /* shorthand */ 01629 int tms; /* timeout for this item */ 01630 int x; /* fd index in channel */ 01631 struct ast_context *con; 01632 01633 if (pu->notquiteyet) { /* Pretend this one isn't here yet */ 01634 pl = pu; 01635 pu = pu->next; 01636 continue; 01637 } 01638 tms = ast_tvdiff_ms(ast_tvnow(), pu->start); 01639 if (tms > pu->parkingtime) { 01640 ast_indicate(chan, AST_CONTROL_UNHOLD); 01641 /* Get chan, exten from derived kludge */ 01642 if (pu->peername[0]) { 01643 char *peername = ast_strdupa(pu->peername); 01644 char *cp = strrchr(peername, '-'); 01645 if (cp) 01646 *cp = 0; 01647 con = ast_context_find(parking_con_dial); 01648 if (!con) { 01649 con = ast_context_create(NULL, parking_con_dial, registrar); 01650 if (!con) 01651 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial); 01652 } 01653 if (con) { 01654 char returnexten[AST_MAX_EXTENSION]; 01655 snprintf(returnexten, sizeof(returnexten), "%s||t", peername); 01656 ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar); 01657 } 01658 set_c_e_p(chan, parking_con_dial, peername, 1); 01659 } else { 01660 /* They've been waiting too long, send them back to where they came. Theoretically they 01661 should have their original extensions and such, but we copy to be on the safe side */ 01662 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 01663 } 01664 01665 post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan); 01666 01667 if (option_verbose > 1) 01668 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); 01669 /* Start up the PBX, or hang them up */ 01670 if (ast_pbx_start(chan)) { 01671 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name); 01672 ast_hangup(chan); 01673 } 01674 /* And take them out of the parking lot */ 01675 if (pl) 01676 pl->next = pu->next; 01677 else 01678 parkinglot = pu->next; 01679 pt = pu; 01680 pu = pu->next; 01681 con = ast_context_find(parking_con); 01682 if (con) { 01683 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL)) 01684 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 01685 else 01686 notify_metermaids(pt->parkingexten, parking_con); 01687 } else 01688 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 01689 free(pt); 01690 } else { /* still within parking time, process descriptors */ 01691 for (x = 0; x < AST_MAX_FDS; x++) { 01692 struct ast_frame *f; 01693 01694 if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds))) 01695 continue; /* nothing on this descriptor */ 01696 01697 if (FD_ISSET(chan->fds[x], &efds)) 01698 ast_set_flag(chan, AST_FLAG_EXCEPTION); 01699 else 01700 ast_clear_flag(chan, AST_FLAG_EXCEPTION); 01701 chan->fdno = x; 01702 01703 /* See if they need servicing */ 01704 f = ast_read(chan); 01705 if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP)) { 01706 if (f) 01707 ast_frfree(f); 01708 post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan); 01709 01710 /* There's a problem, hang them up*/ 01711 if (option_verbose > 1) 01712 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name); 01713 ast_hangup(chan); 01714 /* And take them out of the parking lot */ 01715 if (pl) 01716 pl->next = pu->next; 01717 else 01718 parkinglot = pu->next; 01719 pt = pu; 01720 pu = pu->next; 01721 con = ast_context_find(parking_con); 01722 if (con) { 01723 if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL)) 01724 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 01725 else 01726 notify_metermaids(pt->parkingexten, parking_con); 01727 } else 01728 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 01729 free(pt); 01730 break; 01731 } else { 01732 /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ 01733 ast_frfree(f); 01734 if (pu->moh_trys < 3 && !chan->generatordata) { 01735 if (option_debug) 01736 ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n"); 01737 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 01738 S_OR(parkmohclass, NULL), 01739 !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0); 01740 pu->moh_trys++; 01741 } 01742 goto std; /*! \todo XXX Ick: jumping into an else statement??? XXX */ 01743 } 01744 01745 } /* end for */ 01746 if (x >= AST_MAX_FDS) { 01747 std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */ 01748 if (chan->fds[x] > -1) { 01749 FD_SET(chan->fds[x], &nrfds); 01750 FD_SET(chan->fds[x], &nefds); 01751 if (chan->fds[x] > max) 01752 max = chan->fds[x]; 01753 } 01754 } 01755 /* Keep track of our shortest wait */ 01756 if (tms < ms || ms < 0) 01757 ms = tms; 01758 pl = pu; 01759 pu = pu->next; 01760 } 01761 } 01762 } /* end while */ 01763 ast_mutex_unlock(&parking_lock); 01764 rfds = nrfds; 01765 efds = nefds; 01766 { 01767 struct timeval tv = ast_samp2tv(ms, 1000); 01768 /* Wait for something to happen */ 01769 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL); 01770 } 01771 pthread_testcancel(); 01772 } 01773 return NULL; /* Never reached */ 01774 }
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 949 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().
00950 { 00951 struct ast_app *app; 00952 struct ast_call_feature *feature; 00953 struct ast_channel *work, *idle; 00954 int res; 00955 00956 AST_LIST_LOCK(&feature_list); 00957 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) { 00958 if (!strcasecmp(feature->exten, code)) 00959 break; 00960 } 00961 AST_LIST_UNLOCK(&feature_list); 00962 00963 if (!feature) { /* shouldn't ever happen! */ 00964 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n"); 00965 return -1; 00966 } 00967 00968 if (sense == FEATURE_SENSE_CHAN) { 00969 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 00970 return FEATURE_RETURN_PASSDIGITS; 00971 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 00972 work = chan; 00973 idle = peer; 00974 } else { 00975 work = peer; 00976 idle = chan; 00977 } 00978 } else { 00979 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 00980 return FEATURE_RETURN_PASSDIGITS; 00981 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 00982 work = peer; 00983 idle = chan; 00984 } else { 00985 work = chan; 00986 idle = peer; 00987 } 00988 } 00989 00990 if (!(app = pbx_findapp(feature->app))) { 00991 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app); 00992 return -2; 00993 } 00994 00995 ast_autoservice_start(idle); 00996 00997 if (!ast_strlen_zero(feature->moh_class)) 00998 ast_moh_start(idle, feature->moh_class, NULL); 00999 01000 res = pbx_exec(work, app, feature->app_args); 01001 01002 if (!ast_strlen_zero(feature->moh_class)) 01003 ast_moh_stop(idle); 01004 01005 ast_autoservice_stop(idle); 01006 01007 if (res == AST_PBX_KEEPALIVE) 01008 return FEATURE_RETURN_PBX_KEEPALIVE; 01009 else if (res == AST_PBX_NO_HANGUP_PEER) 01010 return FEATURE_RETURN_NO_HANGUP_PEER; 01011 else if (res) 01012 return FEATURE_RETURN_SUCCESSBREAK; 01013 01014 return FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */ 01015 }
static struct ast_call_feature* find_dynamic_feature | ( | const char * | name | ) | [static] |
find a feature by name
Definition at line 936 of file res_features.c.
References AST_LIST_TRAVERSE, and ast_call_feature::sname.
Referenced by ast_feature_interpret(), and set_config_flags().
00937 { 00938 struct ast_call_feature *tmp; 00939 00940 AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) { 00941 if (!strcasecmp(tmp->sname, name)) 00942 break; 00943 } 00944 00945 return tmp; 00946 }
static int finishup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 620 of file res_features.c.
References ast_autoservice_stop(), AST_CONTROL_UNHOLD, and ast_indicate().
Referenced by builtin_atxfer(), and builtin_blindtransfer().
00621 { 00622 ast_indicate(chan, AST_CONTROL_UNHOLD); 00623 00624 return ast_autoservice_stop(chan); 00625 }
static int handle_parkedcalls | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1976 of file res_features.c.
References ast_cli(), ast_mutex_lock(), ast_mutex_unlock(), parkeduser::chan, parkeduser::context, parkeduser::exten, parkeduser::next, parkeduser::parkingexten, parkinglot, parkeduser::parkingtime, parkeduser::priority, RESULT_SUCCESS, and parkeduser::start.
01977 { 01978 struct parkeduser *cur; 01979 int numparked = 0; 01980 01981 ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel" 01982 , "Context", "Extension", "Pri", "Timeout"); 01983 01984 ast_mutex_lock(&parking_lock); 01985 01986 for (cur = parkinglot; cur; cur = cur->next) { 01987 ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n" 01988 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten 01989 ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)); 01990 01991 numparked++; 01992 } 01993 ast_mutex_unlock(&parking_lock); 01994 ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : ""); 01995 01996 01997 return RESULT_SUCCESS; 01998 }
static int handle_showfeatures | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1935 of file res_features.c.
References ast_cli(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_pickup_ext(), ast_rwlock_rdlock(), ast_rwlock_unlock(), builtin_features, ast_call_feature::default_exten, ast_call_feature::exten, exten, FEATURES_COUNT, ast_call_feature::fname, format, parking_con, parking_ext, parking_start, parking_stop, RESULT_SUCCESS, and ast_call_feature::sname.
01936 { 01937 int i; 01938 struct ast_call_feature *feature; 01939 char format[] = "%-25s %-7s %-7s\n"; 01940 01941 ast_cli(fd, format, "Builtin Feature", "Default", "Current"); 01942 ast_cli(fd, format, "---------------", "-------", "-------"); 01943 01944 ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */ 01945 01946 ast_rwlock_rdlock(&features_lock); 01947 for (i = 0; i < FEATURES_COUNT; i++) 01948 ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten); 01949 ast_rwlock_unlock(&features_lock); 01950 01951 ast_cli(fd, "\n"); 01952 ast_cli(fd, format, "Dynamic Feature", "Default", "Current"); 01953 ast_cli(fd, format, "---------------", "-------", "-------"); 01954 if (AST_LIST_EMPTY(&feature_list)) 01955 ast_cli(fd, "(none)\n"); 01956 else { 01957 AST_LIST_LOCK(&feature_list); 01958 AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) 01959 ast_cli(fd, format, feature->sname, "no def", feature->exten); 01960 AST_LIST_UNLOCK(&feature_list); 01961 } 01962 ast_cli(fd, "\nCall parking\n"); 01963 ast_cli(fd, "------------\n"); 01964 ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext); 01965 ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con); 01966 ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop); 01967 ast_cli(fd,"\n"); 01968 01969 return RESULT_SUCCESS; 01970 }
static int load_config | ( | void | ) | [static] |
Definition at line 2172 of file res_features.c.
References adsipark, ast_config_load(), ast_log(), AST_MAX_EXTENSION, AST_MODULE_LOAD_DECLINE, ast_strlen_zero(), ast_variable_browse(), atxfernoanswertimeout, courtesytone, DEFAULT_FEATURE_DIGIT_TIMEOUT, DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER, DEFAULT_TRANSFER_DIGIT_TIMEOUT, featuredigittimeout, LOG_WARNING, parkaddhints, parkfindnext, parking_con, parking_con_dial, parking_ext, parking_start, parking_stop, parkmohclass, pickup_ext, transferdigittimeout, var, xferfailsound, and xfersound.
02173 { 02174 int start = 0, end = 0; 02175 int res; 02176 struct ast_context *con = NULL; 02177 struct ast_config *cfg = NULL; 02178 struct ast_variable *var = NULL; 02179 char old_parking_ext[AST_MAX_EXTENSION]; 02180 char old_parking_con[AST_MAX_EXTENSION] = ""; 02181 02182 if (!ast_strlen_zero(parking_con)) { 02183 strcpy(old_parking_ext, parking_ext); 02184 strcpy(old_parking_con, parking_con); 02185 } 02186 02187 /* Reset to defaults */ 02188 strcpy(parking_con, "parkedcalls"); 02189 strcpy(parking_con_dial, "park-dial"); 02190 strcpy(parking_ext, "700"); 02191 strcpy(pickup_ext, "*8"); 02192 strcpy(parkmohclass, "default"); 02193 courtesytone[0] = '\0'; 02194 strcpy(xfersound, "beep"); 02195 strcpy(xferfailsound, "pbx-invalid"); 02196 parking_start = 701; 02197 parking_stop = 750; 02198 parkfindnext = 0; 02199 adsipark = 0; 02200 parkaddhints = 0; 02201 02202 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 02203 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 02204 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 02205 02206 cfg = ast_config_load("features.conf"); 02207 if (!cfg) { 02208 ast_log(LOG_WARNING,"Could not load features.conf\n"); 02209 return AST_MODULE_LOAD_DECLINE; 02210 } 02211 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { 02212 if (!strcasecmp(var->name, "parkext")) { 02213 ast_copy_string(parking_ext, var->value, sizeof(parking_ext)); 02214 } else if (!strcasecmp(var->name, "context")) { 02215 ast_copy_string(parking_con, var->value, sizeof(parking_con)); 02216 } else if (!strcasecmp(var->name, "parkingtime")) { 02217 if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) { 02218 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value); 02219 parkingtime = DEFAULT_PARK_TIME; 02220 } else 02221 parkingtime = parkingtime * 1000; 02222 } else if (!strcasecmp(var->name, "parkpos")) { 02223 if (sscanf(var->value, "%d-%d", &start, &end) != 2) { 02224 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); 02225 } else { 02226 parking_start = start; 02227 parking_stop = end; 02228 } 02229 } else if (!strcasecmp(var->name, "findslot")) { 02230 parkfindnext = (!strcasecmp(var->value, "next")); 02231 } else if (!strcasecmp(var->name, "parkinghints")) { 02232 parkaddhints = ast_true(var->value); 02233 } else if (!strcasecmp(var->name, "adsipark")) { 02234 adsipark = ast_true(var->value); 02235 } else if (!strcasecmp(var->name, "transferdigittimeout")) { 02236 if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) { 02237 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value); 02238 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 02239 } else 02240 transferdigittimeout = transferdigittimeout * 1000; 02241 } else if (!strcasecmp(var->name, "featuredigittimeout")) { 02242 if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) { 02243 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value); 02244 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 02245 } 02246 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) { 02247 if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) { 02248 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value); 02249 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 02250 } else 02251 atxfernoanswertimeout = atxfernoanswertimeout * 1000; 02252 } else if (!strcasecmp(var->name, "courtesytone")) { 02253 ast_copy_string(courtesytone, var->value, sizeof(courtesytone)); 02254 } else if (!strcasecmp(var->name, "parkedplay")) { 02255 if (!strcasecmp(var->value, "both")) 02256 parkedplay = 2; 02257 else if (!strcasecmp(var->value, "parked")) 02258 parkedplay = 1; 02259 else 02260 parkedplay = 0; 02261 } else if (!strcasecmp(var->name, "xfersound")) { 02262 ast_copy_string(xfersound, var->value, sizeof(xfersound)); 02263 } else if (!strcasecmp(var->name, "xferfailsound")) { 02264 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound)); 02265 } else if (!strcasecmp(var->name, "pickupexten")) { 02266 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext)); 02267 } else if (!strcasecmp(var->name, "parkedmusicclass")) { 02268 ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass)); 02269 } 02270 } 02271 02272 unmap_features(); 02273 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) { 02274 if (remap_feature(var->name, var->value)) 02275 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); 02276 } 02277 02278 /* Map a key combination to an application*/ 02279 ast_unregister_features(); 02280 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) { 02281 char *tmp_val = ast_strdupa(var->value); 02282 char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 02283 struct ast_call_feature *feature; 02284 02285 /* strsep() sets the argument to NULL if match not found, and it 02286 * is safe to use it with a NULL argument, so we don't check 02287 * between calls. 02288 */ 02289 exten = strsep(&tmp_val,","); 02290 activatedby = strsep(&tmp_val,","); 02291 app = strsep(&tmp_val,","); 02292 app_args = strsep(&tmp_val,","); 02293 moh_class = strsep(&tmp_val,","); 02294 02295 activateon = strsep(&activatedby, "/"); 02296 02297 /*! \todo XXX var_name or app_args ? */ 02298 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) { 02299 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n", 02300 app, exten, activateon, var->name); 02301 continue; 02302 } 02303 02304 AST_LIST_LOCK(&feature_list); 02305 if ((feature = find_dynamic_feature(var->name))) { 02306 AST_LIST_UNLOCK(&feature_list); 02307 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name); 02308 continue; 02309 } 02310 AST_LIST_UNLOCK(&feature_list); 02311 02312 if (!(feature = ast_calloc(1, sizeof(*feature)))) 02313 continue; 02314 02315 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN); 02316 ast_copy_string(feature->app, app, FEATURE_APP_LEN); 02317 ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN); 02318 02319 if (app_args) 02320 ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN); 02321 02322 if (moh_class) 02323 ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN); 02324 02325 ast_copy_string(feature->exten, exten, sizeof(feature->exten)); 02326 feature->operation = feature_exec_app; 02327 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF); 02328 02329 /* Allow caller and calle to be specified for backwards compatability */ 02330 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) 02331 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF); 02332 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) 02333 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER); 02334 else { 02335 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s'," 02336 " must be 'self', or 'peer'\n", var->name); 02337 continue; 02338 } 02339 02340 if (ast_strlen_zero(activatedby)) 02341 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 02342 else if (!strcasecmp(activatedby, "caller")) 02343 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER); 02344 else if (!strcasecmp(activatedby, "callee")) 02345 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE); 02346 else if (!strcasecmp(activatedby, "both")) 02347 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 02348 else { 02349 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s'," 02350 " must be 'caller', or 'callee', or 'both'\n", var->name); 02351 continue; 02352 } 02353 02354 ast_register_feature(feature); 02355 02356 if (option_verbose >= 1) 02357 ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten); 02358 } 02359 ast_config_destroy(cfg); 02360 02361 /* Remove the old parking extension */ 02362 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) { 02363 if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar)) 02364 notify_metermaids(old_parking_ext, old_parking_con); 02365 if (option_debug) 02366 ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con); 02367 } 02368 02369 if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) { 02370 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); 02371 return -1; 02372 } 02373 res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar); 02374 if (parkaddhints) 02375 park_add_hints(parking_con, parking_start, parking_stop); 02376 if (!res) 02377 notify_metermaids(ast_parking_ext(), parking_con); 02378 return res; 02379 02380 }
static int load_module | ( | void | ) | [static] |
Definition at line 2387 of file res_features.c.
References ast_cli_register_multiple(), ast_devstate_prov_add(), ast_manager_register, ast_manager_register2(), ast_pthread_create, ast_register_application(), cli_features, descrip, descrip2, do_parking_thread(), EVENT_FLAG_CALL, load_config(), manager_park(), manager_parking_status(), mandescr_park, metermaidstate(), park_call_exec(), park_exec(), parkcall, parkedcall, parking_con, parking_ext, parking_thread, synopsis, and synopsis2.
02388 { 02389 int res; 02390 02391 memset(parking_ext, 0, sizeof(parking_ext)); 02392 memset(parking_con, 0, sizeof(parking_con)); 02393 02394 if ((res = load_config())) 02395 return res; 02396 ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); 02397 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL); 02398 res = ast_register_application(parkedcall, park_exec, synopsis, descrip); 02399 if (!res) 02400 res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2); 02401 if (!res) { 02402 ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" ); 02403 ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park, 02404 "Park a channel", mandescr_park); 02405 } 02406 02407 res |= ast_devstate_prov_add("Park", metermaidstate); 02408 02409 return res; 02410 }
static int manager_park | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Definition at line 2067 of file res_features.c.
References ast_channel_unlock, ast_get_channel_by_name_locked(), ast_masq_park_call(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), s, and timeout.
Referenced by load_module().
02068 { 02069 const char *channel = astman_get_header(m, "Channel"); 02070 const char *channel2 = astman_get_header(m, "Channel2"); 02071 const char *timeout = astman_get_header(m, "Timeout"); 02072 char buf[BUFSIZ]; 02073 int to = 0; 02074 int res = 0; 02075 int parkExt = 0; 02076 struct ast_channel *ch1, *ch2; 02077 02078 if (ast_strlen_zero(channel)) { 02079 astman_send_error(s, m, "Channel not specified"); 02080 return 0; 02081 } 02082 02083 if (ast_strlen_zero(channel2)) { 02084 astman_send_error(s, m, "Channel2 not specified"); 02085 return 0; 02086 } 02087 02088 ch1 = ast_get_channel_by_name_locked(channel); 02089 if (!ch1) { 02090 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel); 02091 astman_send_error(s, m, buf); 02092 return 0; 02093 } 02094 02095 ch2 = ast_get_channel_by_name_locked(channel2); 02096 if (!ch2) { 02097 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2); 02098 astman_send_error(s, m, buf); 02099 ast_channel_unlock(ch1); 02100 return 0; 02101 } 02102 02103 if (!ast_strlen_zero(timeout)) { 02104 sscanf(timeout, "%d", &to); 02105 } 02106 02107 res = ast_masq_park_call(ch1, ch2, to, &parkExt); 02108 if (!res) { 02109 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT); 02110 astman_send_ack(s, m, "Park successful"); 02111 } else { 02112 astman_send_error(s, m, "Park failure"); 02113 } 02114 02115 ast_channel_unlock(ch1); 02116 ast_channel_unlock(ch2); 02117 02118 return 0; 02119 }
static int manager_parking_status | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Dump lot status.
Definition at line 2020 of file res_features.c.
References ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, parkeduser::next, parkinglot, parkeduser::parkingnum, parkeduser::parkingtime, parkeduser::peername, RESULT_SUCCESS, s, S_OR, and parkeduser::start.
Referenced by load_module().
02021 { 02022 struct parkeduser *cur; 02023 const char *id = astman_get_header(m, "ActionID"); 02024 char idText[256] = ""; 02025 02026 if (!ast_strlen_zero(id)) 02027 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 02028 02029 astman_send_ack(s, m, "Parked calls will follow"); 02030 02031 ast_mutex_lock(&parking_lock); 02032 02033 for (cur = parkinglot; cur; cur = cur->next) { 02034 astman_append(s, "Event: ParkedCall\r\n" 02035 "Exten: %d\r\n" 02036 "Channel: %s\r\n" 02037 "From: %s\r\n" 02038 "Timeout: %ld\r\n" 02039 "CallerID: %s\r\n" 02040 "CallerIDName: %s\r\n" 02041 "%s" 02042 "\r\n", 02043 cur->parkingnum, cur->chan->name, cur->peername, 02044 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL), 02045 S_OR(cur->chan->cid.cid_num, ""), /* XXX in other places it is <unknown> */ 02046 S_OR(cur->chan->cid.cid_name, ""), 02047 idText); 02048 } 02049 02050 astman_append(s, 02051 "Event: ParkedCallsComplete\r\n" 02052 "%s" 02053 "\r\n",idText); 02054 02055 ast_mutex_unlock(&parking_lock); 02056 02057 return RESULT_SUCCESS; 02058 }
static int metermaidstate | ( | const char * | data | ) | [static] |
metermaids callback from devicestate.c
Definition at line 287 of file res_features.c.
References AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, ast_exists_extension(), ast_log(), ast_strdupa, context, exten, LOG_DEBUG, option_debug, and strsep().
Referenced by load_module().
00288 { 00289 int res = AST_DEVICE_INVALID; 00290 char *context = ast_strdupa(data); 00291 char *exten; 00292 00293 exten = strsep(&context, "@"); 00294 if (!context) 00295 return res; 00296 00297 if (option_debug > 3) 00298 ast_log(LOG_DEBUG, "Checking state of exten %s in context %s\n", exten, context); 00299 00300 res = ast_exists_extension(NULL, context, exten, 1, NULL); 00301 00302 if (!res) 00303 return AST_DEVICE_NOT_INUSE; 00304 else 00305 return AST_DEVICE_INUSE; 00306 }
static void notify_metermaids | ( | char * | exten, | |
char * | context | |||
) | [static] |
Notify metermaids that we've changed an extension.
Definition at line 276 of file res_features.c.
References ast_device_state_changed(), ast_log(), LOG_DEBUG, and option_debug.
Referenced by ast_park_call(), do_parking_thread(), and park_exec().
00277 { 00278 if (option_debug > 3) 00279 ast_log(LOG_DEBUG, "Notification of state change to metermaids %s@%s\n", exten, context); 00280 00281 /* Send notification to devicestate subsystem */ 00282 ast_device_state_changed("park:%s@%s", exten, context); 00283 return; 00284 }
static void park_add_hints | ( | char * | context, | |
int | start, | |||
int | stop | |||
) | [static] |
Add parking hints for all defined parking lots.
Definition at line 2158 of file res_features.c.
References ast_add_extension(), AST_MAX_EXTENSION, exten, PRIORITY_HINT, and registrar.
02159 { 02160 int numext; 02161 char device[AST_MAX_EXTENSION]; 02162 char exten[10]; 02163 02164 for (numext = start; numext <= stop; numext++) { 02165 snprintf(exten, sizeof(exten), "%d", numext); 02166 snprintf(device, sizeof(device), "park:%s@%s", exten, context); 02167 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar); 02168 } 02169 }
static int park_call_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Park a call.
Definition at line 1777 of file res_features.c.
References ast_channel::_state, ast_answer(), ast_module_user_add, ast_module_user_remove, ast_park_call(), AST_PBX_KEEPALIVE, ast_safe_sleep(), AST_STATE_UP, ast_module_user::chan, ast_channel::exten, and ast_channel::priority.
Referenced by load_module().
01778 { 01779 /* Data is unused at the moment but could contain a parking 01780 lot context eventually */ 01781 int res = 0; 01782 struct ast_module_user *u; 01783 01784 u = ast_module_user_add(chan); 01785 01786 /* Setup the exten/priority to be s/1 since we don't know 01787 where this call should return */ 01788 strcpy(chan->exten, "s"); 01789 chan->priority = 1; 01790 /* Answer if call is not up */ 01791 if (chan->_state != AST_STATE_UP) 01792 res = ast_answer(chan); 01793 /* Sleep to allow VoIP streams to settle down */ 01794 if (!res) 01795 res = ast_safe_sleep(chan, 1000); 01796 /* Park the call */ 01797 if (!res) 01798 res = ast_park_call(chan, chan, 0, NULL); 01799 01800 ast_module_user_remove(u); 01801 01802 return !res ? AST_PBX_KEEPALIVE : res; 01803 }
static int park_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Pickup parked call.
Definition at line 1806 of file res_features.c.
References ast_channel::_state, ast_answer(), ast_bridge_call(), ast_cdr_setdestchan(), ast_channel_make_compatible(), ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_UNHOLD, AST_FEATURE_REDIRECT, ast_hangup(), ast_indicate(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_mutex_lock(), ast_mutex_unlock(), AST_PBX_NO_HANGUP_PEER, ast_set_flag, AST_STATE_UP, ast_stream_and_wait(), ast_streamfile(), ast_strlen_zero(), ast_verbose(), ast_waitstream(), parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, config, courtesytone, error(), EVENT_FLAG_CALL, free, LOG_WARNING, manager_event(), parkeduser::next, notify_metermaids(), option_verbose, parkedplay, parking_con, parkeduser::parkingexten, parkinglot, parkeduser::parkingnum, pbx_builtin_setvar_helper(), S_OR, and VERBOSE_PREFIX_3.
Referenced by load_module().
01807 { 01808 int res = 0; 01809 struct ast_module_user *u; 01810 struct ast_channel *peer=NULL; 01811 struct parkeduser *pu, *pl=NULL; 01812 struct ast_context *con; 01813 01814 int park; 01815 struct ast_bridge_config config; 01816 01817 if (!data) { 01818 ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n"); 01819 return -1; 01820 } 01821 01822 u = ast_module_user_add(chan); 01823 01824 park = atoi((char *)data); 01825 ast_mutex_lock(&parking_lock); 01826 pu = parkinglot; 01827 while(pu) { 01828 if (pu->parkingnum == park) { 01829 if (pl) 01830 pl->next = pu->next; 01831 else 01832 parkinglot = pu->next; 01833 break; 01834 } 01835 pl = pu; 01836 pu = pu->next; 01837 } 01838 ast_mutex_unlock(&parking_lock); 01839 if (pu) { 01840 peer = pu->chan; 01841 con = ast_context_find(parking_con); 01842 if (con) { 01843 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL)) 01844 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 01845 else 01846 notify_metermaids(pu->parkingexten, parking_con); 01847 } else 01848 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 01849 01850 manager_event(EVENT_FLAG_CALL, "UnParkedCall", 01851 "Exten: %s\r\n" 01852 "Channel: %s\r\n" 01853 "From: %s\r\n" 01854 "CallerID: %s\r\n" 01855 "CallerIDName: %s\r\n", 01856 pu->parkingexten, pu->chan->name, chan->name, 01857 S_OR(pu->chan->cid.cid_num, "<unknown>"), 01858 S_OR(pu->chan->cid.cid_name, "<unknown>") 01859 ); 01860 01861 free(pu); 01862 } 01863 /* JK02: it helps to answer the channel if not already up */ 01864 if (chan->_state != AST_STATE_UP) 01865 ast_answer(chan); 01866 01867 if (peer) { 01868 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */ 01869 01870 if (!ast_strlen_zero(courtesytone)) { 01871 int error = 0; 01872 ast_indicate(peer, AST_CONTROL_UNHOLD); 01873 if (parkedplay == 0) { 01874 error = ast_stream_and_wait(chan, courtesytone, chan->language, ""); 01875 } else if (parkedplay == 1) { 01876 error = ast_stream_and_wait(peer, courtesytone, chan->language, ""); 01877 } else if (parkedplay == 2) { 01878 if (!ast_streamfile(chan, courtesytone, chan->language) && 01879 !ast_streamfile(peer, courtesytone, chan->language)) { 01880 /*! \todo XXX we would like to wait on both! */ 01881 res = ast_waitstream(chan, ""); 01882 if (res >= 0) 01883 res = ast_waitstream(peer, ""); 01884 if (res < 0) 01885 error = 1; 01886 } 01887 } 01888 if (error) { 01889 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 01890 ast_hangup(peer); 01891 return -1; 01892 } 01893 } else 01894 ast_indicate(peer, AST_CONTROL_UNHOLD); 01895 01896 res = ast_channel_make_compatible(chan, peer); 01897 if (res < 0) { 01898 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); 01899 ast_hangup(peer); 01900 return -1; 01901 } 01902 /* This runs sorta backwards, since we give the incoming channel control, as if it 01903 were the person called. */ 01904 if (option_verbose > 2) 01905 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park); 01906 01907 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 01908 ast_cdr_setdestchan(chan->cdr, peer->name); 01909 memset(&config, 0, sizeof(struct ast_bridge_config)); 01910 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 01911 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 01912 res = ast_bridge_call(chan, peer, &config); 01913 01914 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 01915 ast_cdr_setdestchan(chan->cdr, peer->name); 01916 01917 /* Simulate the PBX hanging up */ 01918 if (res != AST_PBX_NO_HANGUP_PEER) 01919 ast_hangup(peer); 01920 return res; 01921 } else { 01922 /*! \todo XXX Play a message XXX */ 01923 if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, "")) 01924 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name); 01925 if (option_verbose > 2) 01926 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park); 01927 res = -1; 01928 } 01929 01930 ast_module_user_remove(u); 01931 01932 return res; 01933 }
static void post_manager_event | ( | const char * | s, | |
char * | parkingexten, | |||
struct ast_channel * | chan | |||
) | [static] |
Definition at line 1594 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().
01595 { 01596 manager_event(EVENT_FLAG_CALL, s, 01597 "Exten: %s\r\n" 01598 "Channel: %s\r\n" 01599 "CallerID: %s\r\n" 01600 "CallerIDName: %s\r\n\r\n", 01601 parkingexten, 01602 chan->name, 01603 S_OR(chan->cid.cid_num, "<unknown>"), 01604 S_OR(chan->cid.cid_name, "<unknown>") 01605 ); 01606 }
static const char* real_ctx | ( | struct ast_channel * | transferer, | |
struct ast_channel * | transferee | |||
) | [static] |
Find the context for the transfer.
Definition at line 628 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().
00629 { 00630 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"); 00631 if (ast_strlen_zero(s)) 00632 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT"); 00633 if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */ 00634 s = transferer->macrocontext; 00635 if (ast_strlen_zero(s)) 00636 s = transferer->context; 00637 return s; 00638 }
static int reload | ( | void | ) | [static] |
Definition at line 2382 of file res_features.c.
References load_config().
02383 { 02384 return load_config(); 02385 }
static int remap_feature | ( | const char * | name, | |
const char * | value | |||
) | [static] |
Definition at line 1027 of file res_features.c.
References ast_rwlock_unlock(), ast_rwlock_wrlock(), builtin_features, exten, and FEATURES_COUNT.
01028 { 01029 int x, res = -1; 01030 01031 ast_rwlock_wrlock(&features_lock); 01032 for (x = 0; x < FEATURES_COUNT; x++) { 01033 if (strcasecmp(builtin_features[x].sname, name)) 01034 continue; 01035 01036 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten)); 01037 res = 0; 01038 break; 01039 } 01040 ast_rwlock_unlock(&features_lock); 01041 01042 return res; 01043 }
static void set_c_e_p | ( | struct ast_channel * | chan, | |
const char * | context, | |||
const char * | ext, | |||
int | pri | |||
) | [static] |
store context, priority and extension
Definition at line 175 of file res_features.c.
References ast_channel::context, ast_channel::exten, and ast_channel::priority.
Referenced by ast_masq_park_call(), builtin_blindtransfer(), and do_parking_thread().
00176 { 00177 ast_copy_string(chan->context, context, sizeof(chan->context)); 00178 ast_copy_string(chan->exten, ext, sizeof(chan->exten)); 00179 chan->priority = pri; 00180 }
static void set_config_flags | ( | struct ast_channel * | chan, | |
struct ast_channel * | peer, | |||
struct ast_bridge_config * | config | |||
) | [static] |
Definition at line 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, builtin_features, config, ast_call_feature::feature_mask, 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 483 of file res_features.c.
References FEATURE_SENSE_PEER.
Referenced by builtin_atxfer(), builtin_automonitor(), builtin_blindtransfer(), and builtin_parkcall().
00485 { 00486 if (sense == FEATURE_SENSE_PEER) { 00487 *caller = peer; 00488 *callee = chan; 00489 } else { 00490 *callee = peer; 00491 *caller = chan; 00492 } 00493 }
static int unload_module | ( | void | ) | [static] |
Definition at line 2413 of file res_features.c.
References ast_cli_unregister_multiple(), ast_devstate_prov_del(), ast_manager_unregister(), ast_module_user_hangup_all, ast_unregister_application(), cli_features, parkcall, and parkedcall.
02414 { 02415 ast_module_user_hangup_all(); 02416 02417 ast_manager_unregister("ParkedCalls"); 02418 ast_manager_unregister("Park"); 02419 ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); 02420 ast_unregister_application(parkcall); 02421 ast_devstate_prov_del("Park"); 02422 return ast_unregister_application(parkedcall); 02423 }
static void unmap_features | ( | void | ) | [static] |
Definition at line 1017 of file res_features.c.
References ast_rwlock_unlock(), ast_rwlock_wrlock(), builtin_features, exten, and FEATURES_COUNT.
01018 { 01019 int x; 01020 01021 ast_rwlock_wrlock(&features_lock); 01022 for (x = 0; x < FEATURES_COUNT; x++) 01023 strcpy(builtin_features[x].exten, builtin_features[x].default_exten); 01024 ast_rwlock_unlock(&features_lock); 01025 }
int adsipark [static] |
int atxfernoanswertimeout [static] |
struct ast_call_feature builtin_features[] [static] |
Definition at line 884 of file res_features.c.
Referenced by ast_feature_interpret(), ast_feature_request_and_dial(), handle_showfeatures(), remap_feature(), set_config_flags(), and unmap_features().
struct ast_cli_entry cli_features[] [static] |
Definition at line 2009 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 2004 of file res_features.c.
char courtesytone[256] [static] |
Courtesy tone
Definition at line 90 of file res_features.c.
Referenced by load_config(), and park_exec().
char* descrip [static] |
Initial value:
"ParkedCall(exten):" "Used to connect to a parked call. This application is always\n" "registered internally and does not need to be explicitly added\n" "into the dialplan, although you should include the 'parkedcalls'\n" "context.\n"
Definition at line 110 of file res_features.c.
char* descrip2 [static] |
Definition at line 120 of file res_features.c.
int featuredigittimeout [static] |
Definition at line 101 of file res_features.c.
char mandescr_park[] [static] |
struct ast_app* monitor_app = NULL [static] |
Definition at line 131 of file res_features.c.
Referenced by ast_bridge_call(), and builtin_automonitor().
int monitor_ok = 1 [static] |
Definition at line 132 of file res_features.c.
int parkaddhints = 0 [static] |
Add parking hints automatically
Definition at line 80 of file res_features.c.
Referenced by load_config().
char* parkcall = "Park" [static] |
char* parkedcall = "ParkedCall" [static] |
int parkedplay = 0 [static] |
Who to play the courtesy tone to
Definition at line 91 of file res_features.c.
Referenced by park_exec().
int parkfindnext [static] |
char parking_con[AST_MAX_EXTENSION] [static] |
Context for which parking is made accessible
Definition at line 82 of file res_features.c.
Referenced by handle_showfeatures(), load_config(), load_module(), and park_exec().
char parking_con_dial[AST_MAX_EXTENSION] [static] |
Context for dialback for parking (KLUDGE)
Definition at line 83 of file res_features.c.
Referenced by load_config().
char parking_ext[AST_MAX_EXTENSION] [static] |
Extension you type to park the call
Definition at line 84 of file res_features.c.
Referenced by handle_showfeatures(), load_config(), and load_module().
int parking_offset [static] |
Definition at line 95 of file res_features.c.
int parking_start [static] |
First available extension for parking
Definition at line 87 of file res_features.c.
Referenced by handle_showfeatures(), and load_config().
int parking_stop [static] |
Last available extension for parking
Definition at line 88 of file res_features.c.
Referenced by handle_showfeatures(), and load_config().
pthread_t parking_thread [static] |
struct parkeduser* parkinglot [static] |
Definition at line 149 of file res_features.c.
Referenced by ast_park_call(), do_parking_thread(), handle_parkedcalls(), manager_parking_status(), and park_exec().
int parkingtime = DEFAULT_PARK_TIME [static] |
No more than 45 seconds parked before you do something with them
Definition at line 81 of file res_features.c.
char parkmohclass[MAX_MUSICCLASS] [static] |
Music class used for parking
Definition at line 86 of file res_features.c.
Referenced by load_config().
char pickup_ext[AST_MAX_EXTENSION] [static] |
char* registrar = "res_features" [static] |
Registrar for operations
Definition at line 105 of file res_features.c.
char showfeatures_help[] [static] |
Initial value:
"Usage: feature list\n" " Lists currently configured features.\n"
Definition at line 1972 of file res_features.c.
char showparked_help[] [static] |
Initial value:
"Usage: show parkedcalls\n" " Lists currently parked calls.\n"
Definition at line 2000 of file res_features.c.
char* synopsis = "Answer a parked call" [static] |
Definition at line 108 of file res_features.c.
char* synopsis2 = "Park yourself" [static] |
Definition at line 118 of file res_features.c.
int transferdigittimeout [static] |
char xferfailsound[256] [static] |
Call transfer failure sound
Definition at line 93 of file res_features.c.
Referenced by load_config().
char xfersound[256] [static] |