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