#include "asterisk.h"
#include "asterisk/_private.h"
#include <pthread.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.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 "asterisk/audiohook.h"
#include "asterisk/global_datastores.h"
#include "asterisk/astobj2.h"
#include "asterisk/cel.h"

Go to the source code of this file.
Data Structures | |
| struct | ast_bridge_thread_obj |
| struct | ast_dial_features |
| struct | ast_park_call_args |
| struct | ast_parkinglot |
| Structure for parking lots which are put in a container. More... | |
| struct | ast_parkinglot::parkinglot_parklist |
| struct | feature_group |
| struct | feature_group_exten |
| struct | feature_groups |
| struct | feature_list |
| struct | parkeduser |
| Description of one parked call, added to a list while active, then removed. The list belongs to a parkinglot. More... | |
Defines | |
| #define | AST_MAX_WATCHERS 256 |
| #define | DEFAULT_ATXFER_CALLBACK_RETRIES 2 |
| #define | DEFAULT_ATXFER_DROP_CALL 0 |
| #define | DEFAULT_ATXFER_LOOP_DELAY 10000 |
| #define | DEFAULT_FEATURE_DIGIT_TIMEOUT 1000 |
| #define | DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000 |
| #define | DEFAULT_PARK_TIME 45000 |
| #define | DEFAULT_PARKINGLOT "default" |
| #define | DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 |
| #define | FEATURES_COUNT ARRAY_LEN(builtin_features) |
| #define | HFS_FORMAT "%-25s %-7s %-7s\n" |
| #define | MAX_DIAL_FEATURE_OPTIONS 30 |
Enumerations | |
| enum | { BRIDGE_OPT_PLAYTONE = (1 << 0), OPT_CALLEE_HANGUP = (1 << 1), OPT_CALLER_HANGUP = (1 << 2), OPT_DURATION_LIMIT = (1 << 3), OPT_DURATION_STOP = (1 << 4), OPT_CALLEE_TRANSFER = (1 << 5), OPT_CALLER_TRANSFER = (1 << 6), OPT_CALLEE_MONITOR = (1 << 7), OPT_CALLER_MONITOR = (1 << 8), OPT_CALLEE_PARK = (1 << 9), OPT_CALLER_PARK = (1 << 10), OPT_CALLEE_KILL = (1 << 11) } |
| enum | { OPT_ARG_DURATION_LIMIT = 0, OPT_ARG_DURATION_STOP, OPT_ARG_ARRAY_SIZE } |
| enum | ast_park_call_options { AST_PARK_OPT_RINGING = (1 << 0), AST_PARK_OPT_RANDOMIZE = (1 << 1), AST_PARK_OPT_SILENCE = (1 << 2) } |
Functions | |
| static void | __fini_feature_groups (void) |
| static void | __fini_feature_list (void) |
| static void | __init_feature_groups (void) |
| static void | __init_feature_list (void) |
| static int | action_bridge (struct mansession *s, const struct message *m) |
| Bridge channels together. | |
| static void | add_features_datastores (struct ast_channel *caller, struct ast_channel *callee, struct ast_bridge_config *config) |
| static int | adsi_announce_park (struct ast_channel *chan, char *parkingexten) |
| Announce call parking by ADSI. | |
| int | ast_bridge_call (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config) |
| bridge the call and set CDR | |
| int | ast_bridge_timelimit (struct ast_channel *chan, struct ast_bridge_config *config, char *parse, struct timeval *calldurationlimit) |
| void | ast_channel_log (char *title, struct ast_channel *chan) |
| int | ast_feature_detect (struct ast_channel *chan, struct ast_flags *features, const char *code, struct ast_call_feature *feature) |
| detect a feature before bridging | |
| int | ast_features_init (void) |
| int | ast_features_reload (void) |
| Reload call features from features.conf. | |
| struct ast_call_feature * | ast_find_call_feature (const char *name) |
| look for a call feature entry by its sname | |
| int | ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout) |
| Park a call via a masqueraded channel. | |
| int | ast_park_call (struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout) |
| Park a call. | |
| const char * | ast_parking_ext (void) |
| Determine system parking extension. | |
| int | ast_pickup_call (struct ast_channel *chan) |
| Pickup a call. | |
| const char * | ast_pickup_ext (void) |
| Determine system call pickup extension. | |
| void | ast_rdlock_call_features (void) |
| void | ast_register_feature (struct ast_call_feature *feature) |
| register new feature into feature_list | |
| void | ast_unlock_call_features (void) |
| 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 void | ast_unregister_groups (void) |
| Remove all feature groups in the list. | |
| static void * | bridge_call_thread (void *data) |
| bridge the call | |
| static void | bridge_call_thread_launch (void *data) |
| create thread for the parked call | |
| static int | bridge_exec (struct ast_channel *chan, const char *data) |
| Bridge channels. | |
| static struct ast_parkinglot * | build_parkinglot (char *name, struct ast_variable *var) |
| Build parkinglot from configuration and chain it in. | |
| static int | builtin_atxfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data) |
| Attended transfer. | |
| static int | builtin_automixmonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data) |
| static int | builtin_automonitor (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data) |
| Monitor a channel by DTMF. | |
| static int | builtin_blindtransfer (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data) |
| Blind transfer user to another extension. | |
| static int | builtin_disconnect (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data) |
| static int | builtin_parkcall (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data) |
| support routing for one touch call parking | |
| static char * | callback_dialoptions (struct ast_flags *features_callee, struct ast_flags *features_caller, char *options, size_t len) |
| static int | check_compat (struct ast_channel *c, struct ast_channel *newchan) |
| make channels compatible | |
| static void | check_goto_on_transfer (struct ast_channel *chan) |
| Check goto on transfer. | |
| static struct ast_parkinglot * | create_parkinglot (char *name) |
| Allocate parking lot structure. | |
| static void | dial_features_destroy (void *data) |
| static void * | dial_features_duplicate (void *data) |
| static void | do_bridge_masquerade (struct ast_channel *chan, struct ast_channel *tmpchan) |
| Actual bridge. | |
| 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, const char *code, int sense, void *data) |
| exec an app by feature | |
| static int | feature_interpret (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense) |
| Check the dynamic features. | |
| static int | feature_interpret_helper (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, char *dynamic_features_buf, struct ast_flags *features, int operation, struct ast_call_feature *feature) |
| Helper function for feature_interpret and ast_feature_detect. | |
| static struct ast_channel * | feature_request_and_dial (struct ast_channel *caller, struct ast_channel *transferee, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, int igncallerstate, const char *language) |
| Get feature and dial. | |
| static int | find_channel_by_group (void *obj, void *arg, void *data, int flags) |
| static struct ast_call_feature * | find_dynamic_feature (const char *name) |
| find a call feature by name | |
| static struct feature_group * | find_group (const char *name) |
| Find a group by name. | |
| struct ast_parkinglot * | find_parkinglot (const char *name) |
| Find parkinglot by name. | |
| static const char * | findparkinglotname (struct ast_channel *chan) |
| Find parking lot name from channel. | |
| static int | finishup (struct ast_channel *chan) |
| static char * | handle_feature_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| CLI command to list configured features. | |
| static char * | handle_features_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_parkedcalls (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| CLI command to list parked calls. | |
| static int | load_config (void) |
| int | manage_parkinglot (struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds, fd_set *nrfds, fd_set *nefds, int *ms, int *max) |
| Run management on parkinglots, called once per parkinglot. | |
| static int | manager_park (struct mansession *s, const struct message *m) |
| Create manager event for parked calls. | |
| static int | manager_parking_status (struct mansession *s, const struct message *m) |
| Dump parking lot status. | |
| static int | masq_park_call (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, int play_announcement, struct ast_park_call_args *args) |
| static int | masq_park_call_announce (struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout) |
| static int | masq_park_call_announce_args (struct ast_channel *rchan, struct ast_channel *peer, struct ast_park_call_args *args) |
| static enum ast_device_state | metermaidstate (const char *data) |
| metermaids callback from devicestate.c | |
| static void | notify_metermaids (const char *exten, char *context, enum ast_device_state state) |
| 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, const char *data) |
| Park a call. | |
| static int | park_call_full (struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args) |
| static int | park_exec (struct ast_channel *chan, const char *data) |
| static int | park_exec_full (struct ast_channel *chan, const char *data, struct ast_parkinglot *parkinglot) |
| Pickup parked call. | |
| static struct parkeduser * | park_space_reserve (struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args) |
| static struct ast_parkinglot * | parkinglot_addref (struct ast_parkinglot *parkinglot) |
| static int | parkinglot_cmp_cb (void *obj, void *arg, int flags) |
| static void | parkinglot_destroy (void *obj) |
| Destroy a parking lot. | |
| static int | parkinglot_hash_cb (const void *obj, const int flags) |
| static void | parkinglot_unref (struct ast_parkinglot *parkinglot) |
| Unreference parkinglot object. If no more references, then go ahead and delete it. | |
| static struct ast_cdr * | pick_unlocked_cdr (struct ast_cdr *cdr) |
| return the first unlocked cdr in a possible chain | |
| static int | play_message_in_bridged_call (struct ast_channel *caller_chan, struct ast_channel *callee_chan, const char *audiofile) |
| Play message to both caller and callee in bridged call, plays synchronously, autoservicing the other channel during the message, so please don't use this for very long messages. | |
| static void | post_manager_event (const char *s, struct parkeduser *pu) |
| Output parking event to manager. | |
| static const char * | real_ctx (struct ast_channel *transferer, struct ast_channel *transferee) |
| Find the context for the transfer. | |
| static struct feature_group * | register_group (const char *fgname) |
| Add new feature group. | |
| static void | register_group_feature (struct feature_group *fg, const char *exten, struct ast_call_feature *feature) |
| Add feature to group. | |
| static int | remap_feature (const char *name, const char *value) |
| static void | set_bridge_features_on_config (struct ast_bridge_config *config, const char *features) |
| static void | set_c_e_p (struct ast_channel *chan, const char *context, const char *ext, int pri) |
| store context, extension and priority | |
| 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 void | unmap_features (void) |
Variables | |
| static int | adsipark |
| static char * | app_bridge = "Bridge" |
| static unsigned int | atxfercallbackretries |
| static unsigned int | atxferdropcall |
| static unsigned int | atxferloopdelay |
| static int | atxfernoanswertimeout |
| static struct ast_app_option | bridge_exec_options [128] = { [ 'p' ] = { .flag = BRIDGE_OPT_PLAYTONE }, [ 'h' ] = { .flag = OPT_CALLEE_HANGUP }, [ 'H' ] = { .flag = OPT_CALLER_HANGUP }, [ 'k' ] = { .flag = OPT_CALLEE_PARK }, [ 'K' ] = { .flag = OPT_CALLER_PARK }, [ 'L' ] = { .flag = OPT_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, [ 'S' ] = { .flag = OPT_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 't' ] = { .flag = OPT_CALLEE_TRANSFER }, [ 'T' ] = { .flag = OPT_CALLER_TRANSFER }, [ 'w' ] = { .flag = OPT_CALLEE_MONITOR }, [ 'W' ] = { .flag = OPT_CALLER_MONITOR }, [ 'x' ] = { .flag = OPT_CALLEE_KILL }, } |
| static struct ast_call_feature | builtin_features [] |
| static struct ast_cli_entry | cli_features [] |
| static int | comebacktoorigin = 1 |
| static char | courtesytone [256] |
| struct ast_parkinglot * | default_parkinglot |
| static struct ast_datastore_info | dial_features_info |
| static int | featuredigittimeout |
| static ast_rwlock_t | features_lock = { 0 } |
| static struct ast_app * | mixmonitor_app = NULL |
| static int | mixmonitor_ok = 1 |
| static struct ast_app * | monitor_app = NULL |
| static int | monitor_ok = 1 |
| static struct ast_app_option | park_call_options [128] = { [ 'r' ] = { .flag = AST_PARK_OPT_RINGING }, [ 'R' ] = { .flag = AST_PARK_OPT_RANDOMIZE }, [ 's' ] = { .flag = AST_PARK_OPT_SILENCE }, } |
| static char * | parkcall = PARK_APP_NAME |
| static char * | parkedcall = "ParkedCall" |
| static int | parkedplay = 0 |
| char | parking_ext [AST_MAX_EXTENSION] |
| static pthread_t | parking_thread |
| static struct ao2_container * | parkinglots |
| The list of parking lots configured. Always at least one - the default parking lot. | |
| static char | pickup_ext [AST_MAX_EXTENSION] |
| static char | pickupfailsound [256] |
| static char | pickupsound [256] |
| static char * | registrar = "features" |
| static struct ast_app * | stopmixmonitor_app = NULL |
| static int | stopmixmonitor_ok = 1 |
| static int | transferdigittimeout |
| static char | xferfailsound [256] |
| static char | xfersound [256] |
Definition in file features.c.
| #define AST_MAX_WATCHERS 256 |
Definition at line 287 of file features.c.
| #define DEFAULT_ATXFER_CALLBACK_RETRIES 2 |
| #define DEFAULT_ATXFER_DROP_CALL 0 |
| #define DEFAULT_ATXFER_LOOP_DELAY 10000 |
| #define DEFAULT_FEATURE_DIGIT_TIMEOUT 1000 |
| #define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000 |
| #define DEFAULT_PARK_TIME 45000 |
| #define DEFAULT_PARKINGLOT "default" |
| #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 |
| #define FEATURES_COUNT ARRAY_LEN(builtin_features) |
Definition at line 1892 of file features.c.
Referenced by ast_find_call_feature(), feature_interpret_helper(), feature_request_and_dial(), handle_feature_show(), remap_feature(), set_config_flags(), and unmap_features().
| #define HFS_FORMAT "%-25s %-7s %-7s\n" |
Referenced by handle_feature_show().
| #define MAX_DIAL_FEATURE_OPTIONS 30 |
| anonymous enum |
Definition at line 4792 of file features.c.
04792 { 04793 BRIDGE_OPT_PLAYTONE = (1 << 0), 04794 OPT_CALLEE_HANGUP = (1 << 1), 04795 OPT_CALLER_HANGUP = (1 << 2), 04796 OPT_DURATION_LIMIT = (1 << 3), 04797 OPT_DURATION_STOP = (1 << 4), 04798 OPT_CALLEE_TRANSFER = (1 << 5), 04799 OPT_CALLER_TRANSFER = (1 << 6), 04800 OPT_CALLEE_MONITOR = (1 << 7), 04801 OPT_CALLER_MONITOR = (1 << 8), 04802 OPT_CALLEE_PARK = (1 << 9), 04803 OPT_CALLER_PARK = (1 << 10), 04804 OPT_CALLEE_KILL = (1 << 11), 04805 };
| anonymous enum |
Definition at line 4807 of file features.c.
04807 { 04808 OPT_ARG_DURATION_LIMIT = 0, 04809 OPT_ARG_DURATION_STOP, 04810 /* note: this entry _MUST_ be the last one in the enum */ 04811 OPT_ARG_ARRAY_SIZE, 04812 };
Options to pass to park_call_full
| AST_PARK_OPT_RINGING | Provide ringing to the parked caller instead of music on hold |
| AST_PARK_OPT_RANDOMIZE | Randomly choose a parking spot for the caller instead of choosing the first one that is available. |
| AST_PARK_OPT_SILENCE | Do not announce the parking number |
Definition at line 655 of file features.c.
00655 { 00656 /*! Provide ringing to the parked caller instead of music on hold */ 00657 AST_PARK_OPT_RINGING = (1 << 0), 00658 /*! Randomly choose a parking spot for the caller instead of choosing 00659 * the first one that is available. */ 00660 AST_PARK_OPT_RANDOMIZE = (1 << 1), 00661 /*! Do not announce the parking number */ 00662 AST_PARK_OPT_SILENCE = (1 << 2), 00663 };
| static void __fini_feature_groups | ( | void | ) | [static] |
| static void __fini_feature_list | ( | void | ) | [static] |
| static void __init_feature_groups | ( | void | ) | [static] |
| static void __init_feature_list | ( | void | ) | [static] |
| static int action_bridge | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Bridge channels together.
| s | ||
| m | Make sure valid channels were specified, send errors if any of the channels could not be found/locked, answer channels if needed, create the placeholder channels and grab the other channels make the channels compatible, send error if we fail doing so setup the bridge thread object and start the bridge. |
| 0 | on success or on incorrect use. | |
| 1 | on failure to bridge channels. |
Definition at line 4414 of file features.c.
References ast_channel::_state, ast_answer(), ast_calloc, ast_channel_alloc, ast_channel_get_by_name_prefix(), ast_channel_make_compatible(), ast_channel_unref, ast_hangup(), ast_log(), AST_STATE_DOWN, AST_STATE_UP, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_waitstream(), astman_get_header(), astman_send_ack(), astman_send_error(), bridge_call_thread_launch(), buf, ast_bridge_thread_obj::chan, do_bridge_masquerade(), errno, ast_channel::linkedid, LOG_WARNING, ast_channel::name, ast_bridge_thread_obj::peer, playtone(), ast_bridge_thread_obj::return_to_pbx, and xfersound.
Referenced by ast_features_init().
04415 { 04416 const char *channela = astman_get_header(m, "Channel1"); 04417 const char *channelb = astman_get_header(m, "Channel2"); 04418 const char *playtone = astman_get_header(m, "Tone"); 04419 struct ast_channel *chana = NULL, *chanb = NULL; 04420 struct ast_channel *tmpchana = NULL, *tmpchanb = NULL; 04421 struct ast_bridge_thread_obj *tobj = NULL; 04422 04423 /* make sure valid channels were specified */ 04424 if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) { 04425 astman_send_error(s, m, "Missing channel parameter in request"); 04426 return 0; 04427 } 04428 04429 /* Start with chana */ 04430 chana = ast_channel_get_by_name_prefix(channela, strlen(channela)); 04431 04432 /* send errors if any of the channels could not be found/locked */ 04433 if (!chana) { 04434 char buf[256]; 04435 snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela); 04436 astman_send_error(s, m, buf); 04437 return 0; 04438 } 04439 04440 /* Answer the channels if needed */ 04441 if (chana->_state != AST_STATE_UP) 04442 ast_answer(chana); 04443 04444 /* create the placeholder channels and grab the other channels */ 04445 if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 04446 NULL, NULL, chana->linkedid, 0, "Bridge/%s", chana->name))) { 04447 astman_send_error(s, m, "Unable to create temporary channel!"); 04448 chana = ast_channel_unref(chana); 04449 return 1; 04450 } 04451 04452 do_bridge_masquerade(chana, tmpchana); 04453 04454 chana = ast_channel_unref(chana); 04455 04456 /* now do chanb */ 04457 chanb = ast_channel_get_by_name_prefix(channelb, strlen(channelb)); 04458 /* send errors if any of the channels could not be found/locked */ 04459 if (!chanb) { 04460 char buf[256]; 04461 snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb); 04462 ast_hangup(tmpchana); 04463 astman_send_error(s, m, buf); 04464 return 0; 04465 } 04466 04467 /* Answer the channels if needed */ 04468 if (chanb->_state != AST_STATE_UP) 04469 ast_answer(chanb); 04470 04471 /* create the placeholder channels and grab the other channels */ 04472 if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 04473 NULL, NULL, chanb->linkedid, 0, "Bridge/%s", chanb->name))) { 04474 astman_send_error(s, m, "Unable to create temporary channels!"); 04475 ast_hangup(tmpchana); 04476 chanb = ast_channel_unref(chanb); 04477 return 1; 04478 } 04479 04480 do_bridge_masquerade(chanb, tmpchanb); 04481 04482 chanb = ast_channel_unref(chanb); 04483 04484 /* make the channels compatible, send error if we fail doing so */ 04485 if (ast_channel_make_compatible(tmpchana, tmpchanb)) { 04486 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name); 04487 astman_send_error(s, m, "Could not make channels compatible for manager bridge"); 04488 ast_hangup(tmpchana); 04489 ast_hangup(tmpchanb); 04490 return 1; 04491 } 04492 04493 /* setup the bridge thread object and start the bridge */ 04494 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) { 04495 ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno)); 04496 astman_send_error(s, m, "Unable to spawn a new bridge thread"); 04497 ast_hangup(tmpchana); 04498 ast_hangup(tmpchanb); 04499 return 1; 04500 } 04501 04502 tobj->chan = tmpchana; 04503 tobj->peer = tmpchanb; 04504 tobj->return_to_pbx = 1; 04505 04506 if (ast_true(playtone)) { 04507 if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) { 04508 if (ast_waitstream(tmpchanb, "") < 0) 04509 ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name); 04510 } 04511 } 04512 04513 bridge_call_thread_launch(tobj); 04514 04515 astman_send_ack(s, m, "Launched bridge thread with success"); 04516 04517 return 0; 04518 }
| static void add_features_datastores | ( | struct ast_channel * | caller, | |
| struct ast_channel * | callee, | |||
| struct ast_bridge_config * | config | |||
| ) | [static] |
Definition at line 2645 of file features.c.
References ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_copy_flags, ast_datastore_alloc, ast_datastore_free(), AST_FLAGS_ALL, ast_log(), ast_datastore::data, DATASTORE_INHERIT_FOREVER, ast_dial_features::features_callee, ast_bridge_config::features_callee, ast_dial_features::features_caller, ast_bridge_config::features_caller, ast_datastore::inheritance, ast_dial_features::is_caller, and LOG_WARNING.
Referenced by ast_bridge_call().
02646 { 02647 struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL; 02648 struct ast_dial_features *callee_features = NULL, *caller_features = NULL; 02649 02650 ast_channel_lock(caller); 02651 ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL); 02652 ast_channel_unlock(caller); 02653 if (!ds_caller_features) { 02654 if (!(ds_caller_features = ast_datastore_alloc(&dial_features_info, NULL))) { 02655 ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n"); 02656 return; 02657 } 02658 if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) { 02659 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n"); 02660 ast_datastore_free(ds_caller_features); 02661 return; 02662 } 02663 ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER; 02664 caller_features->is_caller = 1; 02665 ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL); 02666 ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL); 02667 ds_caller_features->data = caller_features; 02668 ast_channel_lock(caller); 02669 ast_channel_datastore_add(caller, ds_caller_features); 02670 ast_channel_unlock(caller); 02671 } else { 02672 /* If we don't return here, then when we do a builtin_atxfer we will copy the disconnect 02673 * flags over from the atxfer to the caller */ 02674 return; 02675 } 02676 02677 ast_channel_lock(callee); 02678 ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL); 02679 ast_channel_unlock(callee); 02680 if (!ds_callee_features) { 02681 if (!(ds_callee_features = ast_datastore_alloc(&dial_features_info, NULL))) { 02682 ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n"); 02683 return; 02684 } 02685 if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) { 02686 ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n"); 02687 ast_datastore_free(ds_callee_features); 02688 return; 02689 } 02690 ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER; 02691 callee_features->is_caller = 0; 02692 ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL); 02693 ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL); 02694 ds_callee_features->data = callee_features; 02695 ast_channel_lock(callee); 02696 ast_channel_datastore_add(callee, ds_callee_features); 02697 ast_channel_unlock(callee); 02698 } 02699 02700 return; 02701 }
| static int adsi_announce_park | ( | struct ast_channel * | chan, | |
| char * | parkingexten | |||
| ) | [static] |
Announce call parking by ADSI.
| 0 | on success. | |
| -1 | on failure. |
Definition at line 593 of file features.c.
References ADSI_JUST_CENT, ast_adsi_load_session, ast_adsi_print, and justify.
Referenced by park_call_full().
00594 { 00595 int res; 00596 int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT}; 00597 char tmp[256]; 00598 char *message[5] = {NULL, NULL, NULL, NULL, NULL}; 00599 00600 snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten); 00601 message[0] = tmp; 00602 res = ast_adsi_load_session(chan, NULL, 0, 1); 00603 if (res == -1) 00604 return res; 00605 return ast_adsi_print(chan, message, justify, 1); 00606 }
| int ast_bridge_call | ( | struct ast_channel * | chan, | |
| struct ast_channel * | peer, | |||
| struct ast_bridge_config * | config | |||
| ) |
bridge the call and set CDR
Bridge a call, optionally allowing redirection.
| chan,peer,config | Set start time, check for two channels,check if monitor on check for feature activation, create new CDR |
| res | on success. | |
| -1 | on failure to bridge. |
append the event to featurecode. we rely on the string being zero-filled, and not overflowing it.
Definition at line 2712 of file features.c.
References ast_channel::_state, ast_channel::accountcode, ast_cdr::accountcode, add_features_datastores(), ast_channel::amaflags, ast_cdr::amaflags, ast_cdr::answer, ast_channel::appl, AST_BRIDGE_RETRY, ast_bridged_channel(), ast_cdr_alloc(), ast_cdr_answer(), AST_CDR_ANSWERED, ast_cdr_appenduserfield(), ast_cdr_detach(), ast_cdr_discard(), ast_cdr_dup(), ast_cdr_end(), AST_CDR_FLAG_BRIDGED, AST_CDR_FLAG_MAIN, AST_CDR_FLAG_POST_DISABLED, AST_CDR_NULL, ast_cdr_setcid(), ast_cdr_setuserfield(), ast_cdr_specialized_reset(), ast_cdr_start(), ast_cdr_update(), AST_CEL_BRIDGE_END, AST_CEL_BRIDGE_START, ast_cel_report_event(), ast_channel_bridge(), ast_channel_connected_line_macro(), ast_channel_get_by_name(), ast_channel_lock, ast_channel_log(), ast_channel_set_linkgroup(), ast_channel_setoption(), ast_channel_unlock, ast_channel_unref, ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_CONNECTED_LINE, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OPTION, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_string(), ast_debug, ast_default_amaflags, ast_dtmf_stream(), ast_exists_extension(), AST_FEATURE_NO_H_EXTEN, AST_FEATURE_RETURN_PASSDIGITS, AST_FEATURE_RETURN_SUCCESS, AST_FEATURE_WARNING_ACTIVE, AST_FLAG_BRIDGE_HANGUP_DONT, AST_FLAG_BRIDGE_HANGUP_RUN, AST_FLAG_IN_AUTOLOOP, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_free, ast_frfree, ast_indicate(), ast_indicate_data(), ast_log(), ast_opt_end_cdr_before_h_exten, AST_OPTION_FLAG_REQUEST, ast_raw_answer(), ast_set2_flag, ast_set_flag, ast_spawn_extension(), AST_STATE_RINGING, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_tvcmp(), ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), ast_verb, ast_channel::cdr, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, ast_option_header::data, ast_frame::data, ast_channel::data, ast_frame::datalen, ast_cdr::dcontext, ast_cdr::disposition, ast_cdr::dst, ast_cdr::dstchannel, ast_bridge_config::end_bridge_callback, ast_bridge_config::end_bridge_callback_data, ast_channel::exten, f, feature_interpret(), FEATURE_MAX_LEN, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_bridge_config::feature_start_time, ast_bridge_config::feature_timer, featuredigittimeout, ast_bridge_config::features_caller, ast_frame::frametype, ast_cdr::lastapp, ast_cdr::lastdata, LOG_WARNING, monitor_app, monitor_ok, ast_channel::name, ast_cdr::next, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), pick_unlocked_cdr(), ast_channel::priority, ast_frame::ptr, S_OR, set_bridge_features_on_config(), set_config_flags(), ast_cdr::start, ast_frame::subclass, ast_bridge_config::timelimit, ast_channel::uniqueid, ast_cdr::uniqueid, ast_cdr::userfield, and ast_channel::visible_indication.
Referenced by app_exec(), bridge_call_thread(), bridge_exec(), builtin_atxfer(), dial_exec_full(), park_exec_full(), and try_calling().
02713 { 02714 /* Copy voice back and forth between the two channels. Give the peer 02715 the ability to transfer calls with '#<extension' syntax. */ 02716 struct ast_frame *f; 02717 struct ast_channel *who; 02718 char chan_featurecode[FEATURE_MAX_LEN + 1]=""; 02719 char peer_featurecode[FEATURE_MAX_LEN + 1]=""; 02720 char orig_channame[AST_MAX_EXTENSION]; 02721 char orig_peername[AST_MAX_EXTENSION]; 02722 int res; 02723 int diff; 02724 int hasfeatures=0; 02725 int hadfeatures=0; 02726 int autoloopflag; 02727 struct ast_option_header *aoh; 02728 struct ast_cdr *bridge_cdr = NULL; 02729 struct ast_cdr *orig_peer_cdr = NULL; 02730 struct ast_cdr *chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 02731 struct ast_cdr *peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 02732 struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 02733 struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */ 02734 02735 if (chan && peer) { 02736 pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); 02737 pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); 02738 } else if (chan) { 02739 pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); 02740 } 02741 02742 set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES")); 02743 add_features_datastores(chan, peer, config); 02744 02745 /* This is an interesting case. One example is if a ringing channel gets redirected to 02746 * an extension that picks up a parked call. This will make sure that the call taken 02747 * out of parking gets told that the channel it just got bridged to is still ringing. */ 02748 if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) { 02749 ast_indicate(peer, AST_CONTROL_RINGING); 02750 } 02751 02752 if (monitor_ok) { 02753 const char *monitor_exec; 02754 struct ast_channel *src = NULL; 02755 if (!monitor_app) { 02756 if (!(monitor_app = pbx_findapp("Monitor"))) 02757 monitor_ok=0; 02758 } 02759 if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 02760 src = chan; 02761 else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) 02762 src = peer; 02763 if (monitor_app && src) { 02764 char *tmp = ast_strdupa(monitor_exec); 02765 pbx_exec(src, monitor_app, tmp); 02766 } 02767 } 02768 02769 set_config_flags(chan, peer, config); 02770 02771 /* Answer if need be */ 02772 if (chan->_state != AST_STATE_UP) { 02773 if (ast_raw_answer(chan, 1)) { 02774 return -1; 02775 } 02776 } 02777 02778 #ifdef FOR_DEBUG 02779 /* show the two channels and cdrs involved in the bridge for debug & devel purposes */ 02780 ast_channel_log("Pre-bridge CHAN Channel info", chan); 02781 ast_channel_log("Pre-bridge PEER Channel info", peer); 02782 #endif 02783 /* two channels are being marked as linked here */ 02784 ast_channel_set_linkgroup(chan,peer); 02785 02786 /* copy the userfield from the B-leg to A-leg if applicable */ 02787 if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) { 02788 char tmp[256]; 02789 if (!ast_strlen_zero(chan->cdr->userfield)) { 02790 snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield); 02791 ast_cdr_appenduserfield(chan, tmp); 02792 } else 02793 ast_cdr_setuserfield(chan, peer->cdr->userfield); 02794 /* free the peer's cdr without ast_cdr_free complaining */ 02795 ast_free(peer->cdr); 02796 peer->cdr = NULL; 02797 } 02798 ast_copy_string(orig_channame,chan->name,sizeof(orig_channame)); 02799 ast_copy_string(orig_peername,peer->name,sizeof(orig_peername)); 02800 orig_peer_cdr = peer_cdr; 02801 02802 if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) { 02803 02804 if (chan_cdr) { 02805 ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN); 02806 ast_cdr_update(chan); 02807 bridge_cdr = ast_cdr_dup(chan_cdr); 02808 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 02809 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 02810 } else { 02811 /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */ 02812 bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */ 02813 ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel)); 02814 ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel)); 02815 ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid)); 02816 ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp)); 02817 ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata)); 02818 ast_cdr_setcid(bridge_cdr, chan); 02819 bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL; 02820 bridge_cdr->amaflags = chan->amaflags ? chan->amaflags : ast_default_amaflags; 02821 ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode)); 02822 /* Destination information */ 02823 ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst)); 02824 ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext)); 02825 if (peer_cdr) { 02826 bridge_cdr->start = peer_cdr->start; 02827 ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield)); 02828 } else { 02829 ast_cdr_start(bridge_cdr); 02830 } 02831 } 02832 ast_debug(4,"bridge answer set, chan answer set\n"); 02833 /* peer_cdr->answer will be set when a macro runs on the peer; 02834 in that case, the bridge answer will be delayed while the 02835 macro plays on the peer channel. The peer answered the call 02836 before the macro started playing. To the phone system, 02837 this is billable time for the call, even tho the caller 02838 hears nothing but ringing while the macro does its thing. */ 02839 02840 /* Another case where the peer cdr's time will be set, is when 02841 A self-parks by pickup up phone and dialing 700, then B 02842 picks up A by dialing its parking slot; there may be more 02843 practical paths that get the same result, tho... in which 02844 case you get the previous answer time from the Park... which 02845 is before the bridge's start time, so I added in the 02846 tvcmp check to the if below */ 02847 02848 if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) { 02849 bridge_cdr->answer = peer_cdr->answer; 02850 bridge_cdr->disposition = peer_cdr->disposition; 02851 if (chan_cdr) { 02852 chan_cdr->answer = peer_cdr->answer; 02853 chan_cdr->disposition = peer_cdr->disposition; 02854 } 02855 } else { 02856 ast_cdr_answer(bridge_cdr); 02857 if (chan_cdr) { 02858 ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */ 02859 } 02860 } 02861 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) { 02862 if (chan_cdr) { 02863 ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED); 02864 } 02865 if (peer_cdr) { 02866 ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED); 02867 } 02868 } 02869 } 02870 ast_cel_report_event(chan, AST_CEL_BRIDGE_START, NULL, NULL, NULL); 02871 for (;;) { 02872 struct ast_channel *other; /* used later */ 02873 02874 res = ast_channel_bridge(chan, peer, config, &f, &who); 02875 02876 /* When frame is not set, we are probably involved in a situation 02877 where we've timed out. 02878 When frame is set, we'll come this code twice; once for DTMF_BEGIN 02879 and also for DTMF_END. If we flow into the following 'if' for both, then 02880 our wait times are cut in half, as both will subtract from the 02881 feature_timer. Not good! 02882 */ 02883 if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) { 02884 /* Update feature timer for next pass */ 02885 diff = ast_tvdiff_ms(ast_tvnow(), config->feature_start_time); 02886 if (res == AST_BRIDGE_RETRY) { 02887 /* The feature fully timed out but has not been updated. Skip 02888 * the potential round error from the diff calculation and 02889 * explicitly set to expired. */ 02890 config->feature_timer = -1; 02891 } else { 02892 config->feature_timer -= diff; 02893 } 02894 02895 if (hasfeatures) { 02896 if (config->feature_timer <= 0) { 02897 /* Not *really* out of time, just out of time for 02898 digits to come in for features. */ 02899 ast_debug(1, "Timed out for feature!\n"); 02900 if (!ast_strlen_zero(peer_featurecode)) { 02901 ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0); 02902 memset(peer_featurecode, 0, sizeof(peer_featurecode)); 02903 } 02904 if (!ast_strlen_zero(chan_featurecode)) { 02905 ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0); 02906 memset(chan_featurecode, 0, sizeof(chan_featurecode)); 02907 } 02908 if (f) 02909 ast_frfree(f); 02910 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 02911 if (!hasfeatures) { 02912 /* No more digits expected - reset the timer */ 02913 config->feature_timer = 0; 02914 } 02915 hadfeatures = hasfeatures; 02916 /* Continue as we were */ 02917 continue; 02918 } else if (!f) { 02919 /* The bridge returned without a frame and there is a feature in progress. 02920 * However, we don't think the feature has quite yet timed out, so just 02921 * go back into the bridge. */ 02922 continue; 02923 } 02924 } else { 02925 if (config->feature_timer <=0) { 02926 /* We ran out of time */ 02927 config->feature_timer = 0; 02928 who = chan; 02929 if (f) 02930 ast_frfree(f); 02931 f = NULL; 02932 res = 0; 02933 } 02934 } 02935 } 02936 if (res < 0) { 02937 if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer)) { 02938 ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); 02939 } 02940 goto before_you_go; 02941 } 02942 02943 if (!f || (f->frametype == AST_FRAME_CONTROL && 02944 (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 02945 f->subclass == AST_CONTROL_CONGESTION))) { 02946 res = -1; 02947 break; 02948 } 02949 /* many things should be sent to the 'other' channel */ 02950 other = (who == chan) ? peer : chan; 02951 if (f->frametype == AST_FRAME_CONTROL) { 02952 switch (f->subclass) { 02953 case AST_CONTROL_RINGING: 02954 case AST_CONTROL_FLASH: 02955 case -1: 02956 ast_indicate(other, f->subclass); 02957 break; 02958 case AST_CONTROL_CONNECTED_LINE: 02959 if (!ast_channel_connected_line_macro(who, other, f, who != chan, 1)) { 02960 break; 02961 } 02962 /* The implied "else" falls through purposely */ 02963 case AST_CONTROL_HOLD: 02964 case AST_CONTROL_UNHOLD: 02965 ast_indicate_data(other, f->subclass, f->data.ptr, f->datalen); 02966 break; 02967 case AST_CONTROL_OPTION: 02968 aoh = f->data.ptr; 02969 /* Forward option Requests */ 02970 if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) { 02971 ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 02972 f->datalen - sizeof(struct ast_option_header), 0); 02973 } 02974 break; 02975 } 02976 } else if (f->frametype == AST_FRAME_DTMF_BEGIN) { 02977 /* eat it */ 02978 } else if (f->frametype == AST_FRAME_DTMF) { 02979 char *featurecode; 02980 int sense; 02981 02982 hadfeatures = hasfeatures; 02983 /* This cannot overrun because the longest feature is one shorter than our buffer */ 02984 if (who == chan) { 02985 sense = FEATURE_SENSE_CHAN; 02986 featurecode = chan_featurecode; 02987 } else { 02988 sense = FEATURE_SENSE_PEER; 02989 featurecode = peer_featurecode; 02990 } 02991 /*! append the event to featurecode. we rely on the string being zero-filled, and 02992 * not overflowing it. 02993 * \todo XXX how do we guarantee the latter ? 02994 */ 02995 featurecode[strlen(featurecode)] = f->subclass; 02996 /* Get rid of the frame before we start doing "stuff" with the channels */ 02997 ast_frfree(f); 02998 f = NULL; 02999 config->feature_timer = 0; 03000 res = feature_interpret(chan, peer, config, featurecode, sense); 03001 switch(res) { 03002 case AST_FEATURE_RETURN_PASSDIGITS: 03003 ast_dtmf_stream(other, who, featurecode, 0, 0); 03004 /* Fall through */ 03005 case AST_FEATURE_RETURN_SUCCESS: 03006 memset(featurecode, 0, sizeof(chan_featurecode)); 03007 break; 03008 } 03009 if (res >= AST_FEATURE_RETURN_PASSDIGITS) { 03010 res = 0; 03011 } else { 03012 break; 03013 } 03014 hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); 03015 if (hadfeatures && !hasfeatures) { 03016 /* Feature completed or timed out */ 03017 config->feature_timer = 0; 03018 } else if (hasfeatures) { 03019 if (config->timelimit) { 03020 /* No warning next time - we are waiting for future */ 03021 ast_set_flag(config, AST_FEATURE_WARNING_ACTIVE); 03022 } 03023 config->feature_start_time = ast_tvnow(); 03024 config->feature_timer = featuredigittimeout; 03025 ast_debug(1, "Set feature timer to %ld\n", config->feature_timer); 03026 } 03027 } 03028 if (f) 03029 ast_frfree(f); 03030 03031 } 03032 ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, NULL); 03033 before_you_go: 03034 03035 if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) { 03036 ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */ 03037 if (bridge_cdr) { 03038 ast_cdr_discard(bridge_cdr); 03039 /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */ 03040 } 03041 return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */ 03042 } 03043 03044 if (config->end_bridge_callback) { 03045 config->end_bridge_callback(config->end_bridge_callback_data); 03046 } 03047 03048 /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation 03049 * if it were, then chan belongs to a different thread now, and might have been hung up long 03050 * ago. 03051 */ 03052 if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) && 03053 ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) { 03054 struct ast_cdr *swapper = NULL; 03055 char savelastapp[AST_MAX_EXTENSION]; 03056 char savelastdata[AST_MAX_EXTENSION]; 03057 char save_exten[AST_MAX_EXTENSION]; 03058 int save_prio; 03059 int found = 0; /* set if we find at least one match */ 03060 int spawn_error = 0; 03061 03062 autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP); 03063 ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP); 03064 if (bridge_cdr && ast_opt_end_cdr_before_h_exten) { 03065 ast_cdr_end(bridge_cdr); 03066 } 03067 /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge 03068 dialplan code operate on it */ 03069 ast_channel_lock(chan); 03070 if (bridge_cdr) { 03071 swapper = chan->cdr; 03072 ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp)); 03073 ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata)); 03074 chan->cdr = bridge_cdr; 03075 } 03076 ast_copy_string(save_exten, chan->exten, sizeof(save_exten)); 03077 save_prio = chan->priority; 03078 ast_copy_string(chan->exten, "h", sizeof(chan->exten)); 03079 chan->priority = 1; 03080 ast_channel_unlock(chan); 03081 while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num, &found, 1)) == 0) { 03082 chan->priority++; 03083 } 03084 if (found && spawn_error) { 03085 /* Something bad happened, or a hangup has been requested. */ 03086 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 03087 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name); 03088 } 03089 /* swap it back */ 03090 ast_channel_lock(chan); 03091 ast_copy_string(chan->exten, save_exten, sizeof(chan->exten)); 03092 chan->priority = save_prio; 03093 if (bridge_cdr) { 03094 if (chan->cdr == bridge_cdr) { 03095 chan->cdr = swapper; 03096 } else { 03097 bridge_cdr = NULL; 03098 } 03099 } 03100 if (chan->priority != 1 || !spawn_error) { 03101 ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN); 03102 } 03103 ast_channel_unlock(chan); 03104 /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */ 03105 if (bridge_cdr) { 03106 ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp)); 03107 ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata)); 03108 } 03109 ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP); 03110 } 03111 03112 /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */ 03113 new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */ 03114 if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) 03115 ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED); 03116 03117 /* we can post the bridge CDR at this point */ 03118 if (bridge_cdr) { 03119 ast_cdr_end(bridge_cdr); 03120 ast_cdr_detach(bridge_cdr); 03121 } 03122 03123 /* do a specialized reset on the beginning channel 03124 CDR's, if they still exist, so as not to mess up 03125 issues in future bridges; 03126 03127 Here are the rules of the game: 03128 1. The chan and peer channel pointers will not change 03129 during the life of the bridge. 03130 2. But, in transfers, the channel names will change. 03131 between the time the bridge is started, and the 03132 time the channel ends. 03133 Usually, when a channel changes names, it will 03134 also change CDR pointers. 03135 3. Usually, only one of the two channels (chan or peer) 03136 will change names. 03137 4. Usually, if a channel changes names during a bridge, 03138 it is because of a transfer. Usually, in these situations, 03139 it is normal to see 2 bridges running simultaneously, and 03140 it is not unusual to see the two channels that change 03141 swapped between bridges. 03142 5. After a bridge occurs, we have 2 or 3 channels' CDRs 03143 to attend to; if the chan or peer changed names, 03144 we have the before and after attached CDR's. 03145 */ 03146 03147 if (new_chan_cdr) { 03148 struct ast_channel *chan_ptr = NULL; 03149 03150 if (strcasecmp(orig_channame, chan->name) != 0) { 03151 /* old channel */ 03152 if ((chan_ptr = ast_channel_get_by_name(orig_channame))) { 03153 ast_channel_lock(chan_ptr); 03154 if (!ast_bridged_channel(chan_ptr)) { 03155 struct ast_cdr *cur; 03156 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 03157 if (cur == chan_cdr) { 03158 break; 03159 } 03160 } 03161 if (cur) { 03162 ast_cdr_specialized_reset(chan_cdr, 0); 03163 } 03164 } 03165 ast_channel_unlock(chan_ptr); 03166 chan_ptr = ast_channel_unref(chan_ptr); 03167 } 03168 /* new channel */ 03169 ast_cdr_specialized_reset(new_chan_cdr, 0); 03170 } else { 03171 ast_cdr_specialized_reset(chan_cdr, 0); /* nothing changed, reset the chan_cdr */ 03172 } 03173 } 03174 03175 { 03176 struct ast_channel *chan_ptr = NULL; 03177 new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */ 03178 if (new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED) && new_peer_cdr && !ast_test_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED)) 03179 ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */ 03180 if (strcasecmp(orig_peername, peer->name) != 0) { 03181 /* old channel */ 03182 if ((chan_ptr = ast_channel_get_by_name(orig_peername))) { 03183 ast_channel_lock(chan_ptr); 03184 if (!ast_bridged_channel(chan_ptr)) { 03185 struct ast_cdr *cur; 03186 for (cur = chan_ptr->cdr; cur; cur = cur->next) { 03187 if (cur == peer_cdr) { 03188 break; 03189 } 03190 } 03191 if (cur) { 03192 ast_cdr_specialized_reset(peer_cdr, 0); 03193 } 03194 } 03195 ast_channel_unlock(chan_ptr); 03196 chan_ptr = ast_channel_unref(chan_ptr); 03197 } 03198 /* new channel */ 03199 if (new_peer_cdr) { 03200 ast_cdr_specialized_reset(new_peer_cdr, 0); 03201 } 03202 } else { 03203 ast_cdr_specialized_reset(peer_cdr, 0); /* nothing changed, reset the peer_cdr */ 03204 } 03205 } 03206 03207 return res; 03208 }
| int ast_bridge_timelimit | ( | struct ast_channel * | chan, | |
| struct ast_bridge_config * | config, | |||
| char * | parse, | |||
| struct timeval * | calldurationlimit | |||
| ) |
Definition at line 4829 of file features.c.
References ast_channel_lock, ast_channel_unlock, AST_FEATURE_PLAY_WARNING, ast_log(), ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_true(), ast_verb, ast_bridge_config::end_sound, ast_bridge_config::features_callee, ast_bridge_config::features_caller, LOG_WARNING, pbx_builtin_getvar_helper(), ast_bridge_config::play_warning, S_OR, ast_bridge_config::start_sound, strsep(), ast_bridge_config::timelimit, var, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.
Referenced by bridge_exec(), and dial_exec_full().
04831 { 04832 char *stringp = ast_strdupa(parse); 04833 char *limit_str, *warning_str, *warnfreq_str; 04834 const char *var; 04835 int play_to_caller = 0, play_to_callee = 0; 04836 int delta; 04837 04838 limit_str = strsep(&stringp, ":"); 04839 warning_str = strsep(&stringp, ":"); 04840 warnfreq_str = strsep(&stringp, ":"); 04841 04842 config->timelimit = atol(limit_str); 04843 if (warning_str) 04844 config->play_warning = atol(warning_str); 04845 if (warnfreq_str) 04846 config->warning_freq = atol(warnfreq_str); 04847 04848 if (!config->timelimit) { 04849 ast_log(LOG_WARNING, "Bridge does not accept L(%s), hanging up.\n", limit_str); 04850 config->timelimit = config->play_warning = config->warning_freq = 0; 04851 config->warning_sound = NULL; 04852 return -1; /* error */ 04853 } else if ( (delta = config->play_warning - config->timelimit) > 0) { 04854 int w = config->warning_freq; 04855 04856 /* If the first warning is requested _after_ the entire call would end, 04857 and no warning frequency is requested, then turn off the warning. If 04858 a warning frequency is requested, reduce the 'first warning' time by 04859 that frequency until it falls within the call's total time limit. 04860 Graphically: 04861 timelim->| delta |<-playwarning 04862 0__________________|_________________| 04863 | w | | | | 04864 04865 so the number of intervals to cut is 1+(delta-1)/w 04866 */ 04867 04868 if (w == 0) { 04869 config->play_warning = 0; 04870 } else { 04871 config->play_warning -= w * ( 1 + (delta-1)/w ); 04872 if (config->play_warning < 1) 04873 config->play_warning = config->warning_freq = 0; 04874 } 04875 } 04876 04877 ast_channel_lock(chan); 04878 04879 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER"); 04880 play_to_caller = var ? ast_true(var) : 1; 04881 04882 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE"); 04883 play_to_callee = var ? ast_true(var) : 0; 04884 04885 if (!play_to_caller && !play_to_callee) 04886 play_to_caller = 1; 04887 04888 var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE"); 04889 config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft"); 04890 04891 /* The code looking at config wants a NULL, not just "", to decide 04892 * that the message should not be played, so we replace "" with NULL. 04893 * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is 04894 * not found. 04895 */ 04896 04897 var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE"); 04898 config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 04899 04900 var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE"); 04901 config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 04902 04903 ast_channel_unlock(chan); 04904 04905 /* undo effect of S(x) in case they are both used */ 04906 calldurationlimit->tv_sec = 0; 04907 calldurationlimit->tv_usec = 0; 04908 04909 /* more efficient to do it like S(x) does since no advanced opts */ 04910 if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) { 04911 calldurationlimit->tv_sec = config->timelimit / 1000; 04912 calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000; 04913 ast_verb(3, "Setting call duration limit to %.3lf seconds.\n", 04914 calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0); 04915 config->timelimit = play_to_caller = play_to_callee = 04916 config->play_warning = config->warning_freq = 0; 04917 } else { 04918 ast_verb(3, "Limit Data for this call:\n"); 04919 ast_verb(4, "timelimit = %ld\n", config->timelimit); 04920 ast_verb(4, "play_warning = %ld\n", config->play_warning); 04921 ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no"); 04922 ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no"); 04923 ast_verb(4, "warning_freq = %ld\n", config->warning_freq); 04924 ast_verb(4, "start_sound = %s\n", S_OR(config->start_sound, "")); 04925 ast_verb(4, "warning_sound = %s\n", config->warning_sound); 04926 ast_verb(4, "end_sound = %s\n", S_OR(config->end_sound, "")); 04927 } 04928 if (play_to_caller) 04929 ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 04930 if (play_to_callee) 04931 ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 04932 return 0; 04933 }
| void ast_channel_log | ( | char * | title, | |
| struct ast_channel * | chan | |||
| ) |
Definition at line 2580 of file features.c.
References ast_log(), and LOG_NOTICE.
Referenced by ast_bridge_call().
02581 { 02582 ast_log(LOG_NOTICE, "______ %s (%lx)______\n", title, (unsigned long)chan); 02583 ast_log(LOG_NOTICE, "CHAN: name: %s; appl: %s; data: %s; contxt: %s; exten: %s; pri: %d;\n", 02584 chan->name, chan->appl, chan->data, chan->context, chan->exten, chan->priority); 02585 ast_log(LOG_NOTICE, "CHAN: acctcode: %s; dialcontext: %s; amaflags: %x; maccontxt: %s; macexten: %s; macpri: %d;\n", 02586 chan->accountcode, chan->dialcontext, chan->amaflags, chan->macrocontext, chan->macroexten, chan->macropriority); 02587 ast_log(LOG_NOTICE, "CHAN: masq: %p; masqr: %p; _bridge: %p; uniqueID: %s; linkedID:%s\n", 02588 chan->masq, chan->masqr, 02589 chan->_bridge, chan->uniqueid, chan->linkedid); 02590 if (chan->masqr) 02591 ast_log(LOG_NOTICE, "CHAN: masquerading as: %s; cdr: %p;\n", 02592 chan->masqr->name, chan->masqr->cdr); 02593 if (chan->_bridge) 02594 ast_log(LOG_NOTICE, "CHAN: Bridged to %s\n", chan->_bridge->name); 02595 02596 ast_log(LOG_NOTICE, "===== done ====\n"); 02597 }
| int ast_feature_detect | ( | struct ast_channel * | chan, | |
| struct ast_flags * | features, | |||
| const char * | code, | |||
| struct ast_call_feature * | feature | |||
| ) |
detect a feature before bridging
| chan | ||
| ast_flags | ptr | |
| char | ptr of input code |
| ast_call_feature | ptr to be set if found |
Definition at line 2336 of file features.c.
References feature_interpret_helper().
Referenced by detect_disconnect().
02336 { 02337 02338 return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature); 02339 }
| int ast_features_init | ( | void | ) |
Provided by features.c
Definition at line 5103 of file features.c.
References action_bridge(), ao2_container_alloc, ARRAY_LEN, ast_cli_register_multiple(), ast_devstate_prov_add(), ast_manager_register_xml, ast_pthread_create, ast_register_application2(), bridge_exec(), do_parking_thread(), EVENT_FLAG_CALL, load_config(), manager_park(), manager_parking_status(), metermaidstate(), park_call_exec(), park_exec(), parkcall, parkedcall, parking_thread, parkinglot_cmp_cb(), parkinglot_hash_cb(), and parkinglots.
Referenced by main().
05104 { 05105 int res; 05106 05107 ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL); 05108 05109 parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb); 05110 05111 if ((res = load_config())) 05112 return res; 05113 ast_cli_register_multiple(cli_features, ARRAY_LEN(cli_features)); 05114 ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL); 05115 res = ast_register_application2(parkedcall, park_exec, NULL, NULL, NULL); 05116 if (!res) 05117 res = ast_register_application2(parkcall, park_call_exec, NULL, NULL, NULL); 05118 if (!res) { 05119 ast_manager_register_xml("ParkedCalls", 0, manager_parking_status); 05120 ast_manager_register_xml("Park", EVENT_FLAG_CALL, manager_park); 05121 ast_manager_register_xml("Bridge", EVENT_FLAG_CALL, action_bridge); 05122 } 05123 05124 res |= ast_devstate_prov_add("Park", metermaidstate); 05125 05126 return res; 05127 }
| int ast_features_reload | ( | void | ) |
Reload call features from features.conf.
Definition at line 4343 of file features.c.
References load_config().
Referenced by handle_features_reload().
04344 { 04345 int res; 04346 /* Release parking lot list */ 04347 //ASTOBJ_CONTAINER_MARKALL(&parkinglots); 04348 // TODO: I don't think any marking is necessary 04349 04350 /* Reload configuration */ 04351 res = load_config(); 04352 04353 //ASTOBJ_CONTAINER_PRUNE_MARKED(&parkinglots, parkinglot_destroy); 04354 return res; 04355 }
| struct ast_call_feature* ast_find_call_feature | ( | const char * | name | ) | [read] |
look for a call feature entry by its sname
| name | a string ptr, should match "automon", "blindxfer", "atxfer", etc. |
Definition at line 2082 of file features.c.
References FEATURES_COUNT, and ast_call_feature::sname.
Referenced by action_atxfer(), handle_request_info(), and load_config().
02083 { 02084 int x; 02085 for (x = 0; x < FEATURES_COUNT; x++) { 02086 if (!strcasecmp(name, builtin_features[x].sname)) 02087 return &builtin_features[x]; 02088 } 02089 return NULL; 02090 }
| 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. | |
| timeout | is a timeout in milliseconds | |
| extout | is a parameter to an int that will hold the parked location, or NULL if you want. |
| 0 | on success. | |
| -1 | on failure. |
Definition at line 1010 of file features.c.
References masq_park_call().
Referenced by __analog_ss_thread(), analog_ss_thread(), handle_exec(), handle_soft_key_event_message(), handle_stimulus_message(), manager_park(), mgcp_ss(), parkandannounce_exec(), and rpt_exec().
01011 { 01012 return masq_park_call(rchan, peer, timeout, extout, 0, NULL); 01013 }
| int ast_park_call | ( | struct ast_channel * | chan, | |
| struct ast_channel * | peer, | |||
| int | timeout, | |||
| int * | extout | |||
| ) |
Park a call.
Park a call and read back parked location.
Definition at line 944 of file features.c.
References park_call_full(), and ast_park_call_args::timeout.
Referenced by iax_park_thread(), and sip_park_thread().
00945 { 00946 struct ast_park_call_args args = { 00947 .timeout = timeout, 00948 .extout = extout, 00949 }; 00950 00951 return park_call_full(chan, peer, &args); 00952 }
| const char* ast_parking_ext | ( | void | ) |
Determine system parking extension.
Definition at line 431 of file features.c.
References parking_ext.
Referenced by __analog_ss_thread(), analog_ss_thread(), build_parkinglot(), builtin_atxfer(), builtin_blindtransfer(), dp_lookup(), handle_request_refer(), load_config(), mgcp_ss(), and socket_process().
00432 { 00433 return parking_ext; 00434 }
| int ast_pickup_call | ( | struct ast_channel * | chan | ) |
Pickup a call.
| chan | channel that initiated pickup. |
Definition at line 4733 of file features.c.
References ast_answer(), ast_channel_callback(), ast_channel_connected_line_macro(), ast_channel_lock_both, ast_channel_masquerade(), ast_channel_queue_connected_line_update(), ast_channel_unlock, ast_channel_unref, ast_channel_update_connected_line(), AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, AST_CONTROL_ANSWER, ast_debug, ast_log(), ast_party_connected_line_collect_caller(), ast_queue_control(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_channel::cid, ast_channel::connected, find_channel_by_group(), LOG_WARNING, ast_channel::name, pickupfailsound, pickupsound, and ast_party_connected_line::source.
Referenced by __analog_ss_thread(), analog_ss_thread(), cb_events(), handle_request_invite(), mgcp_ss(), and pickup_exec().
04734 { 04735 struct ast_channel *cur; 04736 struct ast_party_connected_line connected_caller; 04737 int res; 04738 const char *chan_name; 04739 const char *cur_name; 04740 04741 if (!(cur = ast_channel_callback(find_channel_by_group, NULL, chan, 0))) { 04742 ast_debug(1, "No call pickup possible...\n"); 04743 if (!ast_strlen_zero(pickupfailsound)) { 04744 ast_stream_and_wait(chan, pickupfailsound, ""); 04745 } 04746 return -1; 04747 } 04748 04749 ast_channel_lock_both(cur, chan); 04750 04751 cur_name = ast_strdupa(cur->name); 04752 chan_name = ast_strdupa(chan->name); 04753 04754 ast_debug(1, "Call pickup on chan '%s' by '%s'\n", cur_name, chan_name); 04755 04756 connected_caller = cur->connected; 04757 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 04758 if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) { 04759 ast_channel_update_connected_line(chan, &connected_caller); 04760 } 04761 04762 ast_party_connected_line_collect_caller(&connected_caller, &chan->cid); 04763 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 04764 ast_channel_queue_connected_line_update(chan, &connected_caller); 04765 04766 ast_channel_unlock(cur); 04767 ast_channel_unlock(chan); 04768 04769 if (ast_answer(chan)) { 04770 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name); 04771 } 04772 04773 if (ast_queue_control(chan, AST_CONTROL_ANSWER)) { 04774 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name); 04775 } 04776 04777 if ((res = ast_channel_masquerade(cur, chan))) { 04778 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan_name, cur_name); 04779 } 04780 04781 if (!ast_strlen_zero(pickupsound)) { 04782 ast_stream_and_wait(cur, pickupsound, ""); 04783 } 04784 04785 cur = ast_channel_unref(cur); 04786 04787 return res; 04788 }
| const char* ast_pickup_ext | ( | void | ) |
Determine system call pickup extension.
Definition at line 436 of file features.c.
References pickup_ext.
Referenced by __analog_ss_thread(), analog_ss_thread(), cb_events(), get_destination(), handle_feature_show(), handle_request_invite(), and mgcp_ss().
00437 { 00438 return pickup_ext; 00439 }
| void ast_rdlock_call_features | ( | void | ) |
Definition at line 2072 of file features.c.
References ast_rwlock_rdlock(), and features_lock.
Referenced by handle_request_info().
02073 { 02074 ast_rwlock_rdlock(&features_lock); 02075 }
| void ast_register_feature | ( | struct ast_call_feature * | feature | ) |
register new feature into feature_list
register new feature into feature_set
Definition at line 1909 of file features.c.
References ast_log(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, ast_call_feature::feature_entry, LOG_NOTICE, and ast_call_feature::sname.
Referenced by load_config().
01910 { 01911 if (!feature) { 01912 ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); 01913 return; 01914 } 01915 01916 AST_RWLIST_WRLOCK(&feature_list); 01917 AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry); 01918 AST_RWLIST_UNLOCK(&feature_list); 01919 01920 ast_verb(2, "Registered Feature '%s'\n",feature->sname); 01921 }
| void ast_unlock_call_features | ( | void | ) |
Definition at line 2077 of file features.c.
References ast_rwlock_unlock(), and features_lock.
Referenced by handle_request_info().
02078 { 02079 ast_rwlock_unlock(&features_lock); 02080 }
| 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 1997 of file features.c.
References ast_free, AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.
01998 { 01999 if (!feature) { 02000 return; 02001 } 02002 02003 AST_RWLIST_WRLOCK(&feature_list); 02004 AST_RWLIST_REMOVE(&feature_list, feature, feature_entry); 02005 AST_RWLIST_UNLOCK(&feature_list); 02006 02007 ast_free(feature); 02008 }
| static void ast_unregister_features | ( | void | ) | [static] |
Remove all features in the list.
Definition at line 2011 of file features.c.
References ast_free, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and ast_call_feature::feature_entry.
Referenced by load_config().
02012 { 02013 struct ast_call_feature *feature; 02014 02015 AST_RWLIST_WRLOCK(&feature_list); 02016 while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) { 02017 ast_free(feature); 02018 } 02019 AST_RWLIST_UNLOCK(&feature_list); 02020 }
| static void ast_unregister_groups | ( | void | ) | [static] |
Remove all feature groups in the list.
Definition at line 2037 of file features.c.
References ast_free, AST_LIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_string_field_free_memory, and feature_group::features.
Referenced by load_config().
02038 { 02039 struct feature_group *fg; 02040 struct feature_group_exten *fge; 02041 02042 AST_RWLIST_WRLOCK(&feature_groups); 02043 while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) { 02044 while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) { 02045 ast_string_field_free_memory(fge); 02046 ast_free(fge); 02047 } 02048 02049 ast_string_field_free_memory(fg); 02050 ast_free(fg); 02051 } 02052 AST_RWLIST_UNLOCK(&feature_groups); 02053 }
| static void* bridge_call_thread | ( | void * | data | ) | [static] |
bridge the call
| data | thread bridge. |
Definition at line 528 of file features.c.
References ast_channel::appl, ast_bridge_call(), ast_check_hangup(), ast_free, ast_hangup(), ast_log(), ast_pbx_start(), AST_PBX_SUCCESS, ast_bridge_thread_obj::bconfig, ast_bridge_thread_obj::chan, ast_channel::data, LOG_VERBOSE, LOG_WARNING, ast_channel::name, ast_bridge_thread_obj::peer, and ast_bridge_thread_obj::return_to_pbx.
Referenced by bridge_call_thread_launch().
00529 { 00530 struct ast_bridge_thread_obj *tobj = data; 00531 int res; 00532 00533 tobj->chan->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge"; 00534 tobj->chan->data = tobj->peer->name; 00535 tobj->peer->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge"; 00536 tobj->peer->data = tobj->chan->name; 00537 00538 ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig); 00539 00540 if (tobj->return_to_pbx) { 00541 if (!ast_check_hangup(tobj->peer)) { 00542 ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", tobj->peer->name); 00543 res = ast_pbx_start(tobj->peer); 00544 if (res != AST_PBX_SUCCESS) 00545 ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", tobj->peer->name); 00546 } else 00547 ast_hangup(tobj->peer); 00548 if (!ast_check_hangup(tobj->chan)) { 00549 ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", tobj->chan->name); 00550 res = ast_pbx_start(tobj->chan); 00551 if (res != AST_PBX_SUCCESS) 00552 ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", tobj->chan->name); 00553 } else 00554 ast_hangup(tobj->chan); 00555 } else { 00556 ast_hangup(tobj->chan); 00557 ast_hangup(tobj->peer); 00558 } 00559 00560 ast_free(tobj); 00561 00562 return NULL; 00563 }
| static void bridge_call_thread_launch | ( | void * | data | ) | [static] |
create thread for the parked call
| data | Create thread and attributes, call bridge_call_thread |
Definition at line 571 of file features.c.
References ast_pthread_create, bridge_call_thread(), and thread.
Referenced by action_bridge(), and builtin_atxfer().
00572 { 00573 pthread_t thread; 00574 pthread_attr_t attr; 00575 struct sched_param sched; 00576 00577 pthread_attr_init(&attr); 00578 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 00579 ast_pthread_create(&thread, &attr, bridge_call_thread, data); 00580 pthread_attr_destroy(&attr); 00581 memset(&sched, 0, sizeof(sched)); 00582 pthread_setschedparam(thread, SCHED_RR, &sched); 00583 }
| static int bridge_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
Bridge channels.
| chan | ||
| data | channel to bridge with. |
Definition at line 4945 of file features.c.
References ast_channel::_state, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_bridge_call(), ast_bridge_timelimit(), ast_channel_alloc, ast_channel_get_by_name_prefix(), ast_channel_make_compatible(), ast_channel_unlock, ast_channel_unref, ast_check_hangup(), ast_debug, AST_DECLARE_APP_ARGS, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, ast_free, ast_hangup(), ast_log(), ast_pbx_start(), AST_PBX_SUCCESS, ast_set_flag, AST_STANDARD_APP_ARGS, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_waitstream(), bridge_exec_options, BRIDGE_OPT_PLAYTONE, ast_channel::context, do_bridge_masquerade(), ast_bridge_config::end_sound, EVENT_FLAG_CALL, ast_channel::exten, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_channel::language, ast_channel::linkedid, LOG_WARNING, manager_event, ast_channel::name, OPT_ARG_ARRAY_SIZE, OPT_ARG_DURATION_LIMIT, OPT_CALLEE_HANGUP, OPT_CALLEE_KILL, OPT_CALLEE_MONITOR, OPT_CALLEE_PARK, OPT_CALLEE_TRANSFER, OPT_CALLER_HANGUP, OPT_CALLER_MONITOR, OPT_CALLER_PARK, OPT_CALLER_TRANSFER, OPT_DURATION_LIMIT, pbx_builtin_setvar_helper(), ast_channel::priority, ast_bridge_config::start_sound, ast_bridge_config::warning_sound, and xfersound.
Referenced by ast_features_init().
04946 { 04947 struct ast_channel *current_dest_chan, *final_dest_chan; 04948 char *tmp_data = NULL; 04949 struct ast_flags opts = { 0, }; 04950 struct ast_bridge_config bconfig = { { 0, }, }; 04951 char *opt_args[OPT_ARG_ARRAY_SIZE]; 04952 struct timeval calldurationlimit = { 0, }; 04953 04954 AST_DECLARE_APP_ARGS(args, 04955 AST_APP_ARG(dest_chan); 04956 AST_APP_ARG(options); 04957 ); 04958 04959 if (ast_strlen_zero(data)) { 04960 ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n"); 04961 return -1; 04962 } 04963 04964 tmp_data = ast_strdupa(data); 04965 AST_STANDARD_APP_ARGS(args, tmp_data); 04966 if (!ast_strlen_zero(args.options)) 04967 ast_app_parse_options(bridge_exec_options, &opts, opt_args, args.options); 04968 04969 /* avoid bridge with ourselves */ 04970 if (!strncmp(chan->name, args.dest_chan, 04971 strlen(chan->name) < strlen(args.dest_chan) ? 04972 strlen(chan->name) : strlen(args.dest_chan))) { 04973 ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name); 04974 manager_event(EVENT_FLAG_CALL, "BridgeExec", 04975 "Response: Failed\r\n" 04976 "Reason: Unable to bridge channel to itself\r\n" 04977 "Channel1: %s\r\n" 04978 "Channel2: %s\r\n", 04979 chan->name, args.dest_chan); 04980 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP"); 04981 return 0; 04982 } 04983 04984 /* make sure we have a valid end point */ 04985 if (!(current_dest_chan = ast_channel_get_by_name_prefix(args.dest_chan, 04986 strlen(args.dest_chan)))) { 04987 ast_log(LOG_WARNING, "Bridge failed because channel %s does not exists or we " 04988 "cannot get its lock\n", args.dest_chan); 04989 manager_event(EVENT_FLAG_CALL, "BridgeExec", 04990 "Response: Failed\r\n" 04991 "Reason: Cannot grab end point\r\n" 04992 "Channel1: %s\r\n" 04993 "Channel2: %s\r\n", chan->name, args.dest_chan); 04994 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT"); 04995 return 0; 04996 } 04997 04998 /* answer the channel if needed */ 04999 if (current_dest_chan->_state != AST_STATE_UP) { 05000 ast_answer(current_dest_chan); 05001 } 05002 05003 /* try to allocate a place holder where current_dest_chan will be placed */ 05004 if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 05005 NULL, NULL, current_dest_chan->linkedid, 0, "Bridge/%s", current_dest_chan->name))) { 05006 ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan); 05007 manager_event(EVENT_FLAG_CALL, "BridgeExec", 05008 "Response: Failed\r\n" 05009 "Reason: cannot create placeholder\r\n" 05010 "Channel1: %s\r\n" 05011 "Channel2: %s\r\n", chan->name, args.dest_chan); 05012 } 05013 05014 ast_channel_unlock(current_dest_chan); 05015 05016 do_bridge_masquerade(current_dest_chan, final_dest_chan); 05017 05018 /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */ 05019 /* try to make compatible, send error if we fail */ 05020 if (ast_channel_make_compatible(chan, final_dest_chan) < 0) { 05021 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name); 05022 manager_event(EVENT_FLAG_CALL, "BridgeExec", 05023 "Response: Failed\r\n" 05024 "Reason: Could not make channels compatible for bridge\r\n" 05025 "Channel1: %s\r\n" 05026 "Channel2: %s\r\n", chan->name, final_dest_chan->name); 05027 ast_hangup(final_dest_chan); /* may be we should return this channel to the PBX? */ 05028 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE"); 05029 current_dest_chan = ast_channel_unref(current_dest_chan); 05030 return 0; 05031 } 05032 05033 /* Report that the bridge will be successfull */ 05034 manager_event(EVENT_FLAG_CALL, "BridgeExec", 05035 "Response: Success\r\n" 05036 "Channel1: %s\r\n" 05037 "Channel2: %s\r\n", chan->name, final_dest_chan->name); 05038 05039 /* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */ 05040 if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) { 05041 if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) { 05042 if (ast_waitstream(final_dest_chan, "") < 0) 05043 ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name); 05044 } 05045 } 05046 05047 current_dest_chan = ast_channel_unref(current_dest_chan); 05048 05049 if (ast_test_flag(&opts, OPT_DURATION_LIMIT) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])) { 05050 if (ast_bridge_timelimit(chan, &bconfig, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit)) 05051 goto done; 05052 } 05053 05054 if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER)) 05055 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_REDIRECT); 05056 if (ast_test_flag(&opts, OPT_CALLER_TRANSFER)) 05057 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_REDIRECT); 05058 if (ast_test_flag(&opts, OPT_CALLEE_HANGUP)) 05059 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 05060 if (ast_test_flag(&opts, OPT_CALLER_HANGUP)) 05061 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 05062 if (ast_test_flag(&opts, OPT_CALLEE_MONITOR)) 05063 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_AUTOMON); 05064 if (ast_test_flag(&opts, OPT_CALLER_MONITOR)) 05065 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_AUTOMON); 05066 if (ast_test_flag(&opts, OPT_CALLEE_PARK)) 05067 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_PARKCALL); 05068 if (ast_test_flag(&opts, OPT_CALLER_PARK)) 05069 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_PARKCALL); 05070 05071 ast_bridge_call(chan, final_dest_chan, &bconfig); 05072 05073 /* the bridge has ended, set BRIDGERESULT to SUCCESS. If the other channel has not been hung up, return it to the PBX */ 05074 pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS"); 05075 if (!ast_check_hangup(final_dest_chan) && !ast_test_flag(&opts, OPT_CALLEE_KILL)) { 05076 ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n", 05077 final_dest_chan->context, final_dest_chan->exten, 05078 final_dest_chan->priority, final_dest_chan->name); 05079 05080 if (ast_pbx_start(final_dest_chan) != AST_PBX_SUCCESS) { 05081 ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name); 05082 ast_hangup(final_dest_chan); 05083 } else 05084 ast_debug(1, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name); 05085 } else { 05086 ast_debug(1, "hangup chan %s since the other endpoint has hung up or the x flag was passed\n", final_dest_chan->name); 05087 ast_hangup(final_dest_chan); 05088 } 05089 done: 05090 if (bconfig.warning_sound) { 05091 ast_free((char *)bconfig.warning_sound); 05092 } 05093 if (bconfig.end_sound) { 05094 ast_free((char *)bconfig.end_sound); 05095 } 05096 if (bconfig.start_sound) { 05097 ast_free((char *)bconfig.start_sound); 05098 } 05099 05100 return 0; 05101 }
| static struct ast_parkinglot* build_parkinglot | ( | char * | name, | |
| struct ast_variable * | var | |||
| ) | [static, read] |
Build parkinglot from configuration and chain it in.
Definition at line 3818 of file features.c.
References ao2_link, ao2_lock(), ao2_unlock(), ast_add_extension2(), ast_context_find_or_create(), ast_copy_string(), ast_free_ptr, ast_log(), ast_parking_ext(), ast_strlen_zero(), create_parkinglot(), DEFAULT_PARK_TIME, find_parkinglot(), ast_variable::lineno, LOG_DEBUG, LOG_ERROR, LOG_WARNING, ast_parkinglot::mohclass, ast_variable::name, ast_variable::next, option_debug, parkcall, ast_parkinglot::parkfindnext, ast_parkinglot::parking_con, ast_parkinglot::parking_con_dial, ast_parkinglot::parking_start, ast_parkinglot::parking_stop, parkinglot_destroy(), parkinglot_unref(), parkinglots, ast_parkinglot::parkingtime, registrar, strdup, and ast_variable::value.
Referenced by load_config().
03819 { 03820 struct ast_parkinglot *parkinglot; 03821 struct ast_context *con = NULL; 03822 03823 struct ast_variable *confvar = var; 03824 int error = 0; 03825 int start = 0, end = 0; 03826 int oldparkinglot = 0; 03827 03828 parkinglot = find_parkinglot(name); 03829 if (parkinglot) 03830 oldparkinglot = 1; 03831 else 03832 parkinglot = create_parkinglot(name); 03833 03834 if (!parkinglot) 03835 return NULL; 03836 03837 ao2_lock(parkinglot); 03838 03839 if (option_debug) 03840 ast_log(LOG_DEBUG, "Building parking lot %s\n", name); 03841 03842 /* Do some config stuff */ 03843 while(confvar) { 03844 if (!strcasecmp(confvar->name, "context")) { 03845 ast_copy_string(parkinglot->parking_con, confvar->value, sizeof(parkinglot->parking_con)); 03846 } else if (!strcasecmp(confvar->name, "parkingtime")) { 03847 if ((sscanf(confvar->value, "%30d", &parkinglot->parkingtime) != 1) || (parkinglot->parkingtime < 1)) { 03848 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", confvar->value); 03849 parkinglot->parkingtime = DEFAULT_PARK_TIME; 03850 } else 03851 parkinglot->parkingtime = parkinglot->parkingtime * 1000; 03852 } else if (!strcasecmp(confvar->name, "parkpos")) { 03853 if (sscanf(confvar->value, "%30d-%30d", &start, &end) != 2) { 03854 ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers at line %d of parking.conf\n", confvar->lineno); 03855 error = 1; 03856 } else { 03857 parkinglot->parking_start = start; 03858 parkinglot->parking_stop = end; 03859 } 03860 } else if (!strcasecmp(confvar->name, "findslot")) { 03861 parkinglot->parkfindnext = (!strcasecmp(confvar->value, "next")); 03862 } 03863 confvar = confvar->next; 03864 } 03865 /* make sure parkingtime is set if not specified */ 03866 if (parkinglot->parkingtime == 0) { 03867 parkinglot->parkingtime = DEFAULT_PARK_TIME; 03868 } 03869 03870 if (!var) { /* Default parking lot */ 03871 ast_copy_string(parkinglot->parking_con, "parkedcalls", sizeof(parkinglot->parking_con)); 03872 ast_copy_string(parkinglot->parking_con_dial, "park-dial", sizeof(parkinglot->parking_con_dial)); 03873 ast_copy_string(parkinglot->mohclass, "default", sizeof(parkinglot->mohclass)); 03874 } 03875 03876 /* Check for errors */ 03877 if (ast_strlen_zero(parkinglot->parking_con)) { 03878 ast_log(LOG_WARNING, "Parking lot %s lacks context\n", name); 03879 error = 1; 03880 } 03881 03882 /* Create context */ 03883 if (!error && !(con = ast_context_find_or_create(NULL, NULL, parkinglot->parking_con, registrar))) { 03884 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parkinglot->parking_con); 03885 error = 1; 03886 } 03887 03888 /* Add a parking extension into the context */ 03889 if (!error && !oldparkinglot) { 03890 if (!ast_strlen_zero(ast_parking_ext())) { 03891 if (ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), ast_free_ptr, registrar) == -1) 03892 error = 1; 03893 } 03894 } 03895 03896 ao2_unlock(parkinglot); 03897 03898 if (error) { 03899 ast_log(LOG_WARNING, "Parking %s not open for business. Configuration error.\n", name); 03900 parkinglot_destroy(parkinglot); 03901 return NULL; 03902 } 03903 if (option_debug) 03904 ast_log(LOG_DEBUG, "Parking %s now open for business. (start exten %d end %d)\n", name, start, end); 03905 03906 03907 /* Move it into the list, if it wasn't already there */ 03908 if (!oldparkinglot) { 03909 ao2_link(parkinglots, parkinglot); 03910 } 03911 parkinglot_unref(parkinglot); 03912 03913 return parkinglot; 03914 }
| static int builtin_atxfer | ( | struct ast_channel * | chan, | |
| struct ast_channel * | peer, | |||
| struct ast_bridge_config * | config, | |||
| const char * | code, | |||
| int | sense, | |||
| void * | data | |||
| ) | [static] |
Attended transfer.
| chan | transfered user | |
| peer | person transfering call | |
| config | ||
| code | ||
| sense | feature options | |
| data | Get extension to transfer to, if you cannot generate channel (or find extension) return to host channel. After called channel answered wait for hangup of transferer, bridge call between transfer peer (taking them off hold) to attended transfer channel. |
Definition at line 1513 of file 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_calloc, AST_CEL_ATTENDEDTRANSFER, ast_cel_report_event(), ast_channel_alloc, ast_channel_connected_line_macro(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_masquerade(), ast_channel_unlock, ast_channel_update_connected_line(), ast_check_hangup(), ast_clear_flag, ast_connected_line_copy_from_caller(), AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER, AST_CONTROL_BUSY, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, ast_copy_flags, ast_debug, AST_DIGIT_ANY, ast_exists_extension(), ast_explicit_goto(), AST_FEATURE_DISCONNECT, AST_FEATURE_RETURN_SUCCESS, AST_FLAGS_ALL, ast_frfree, ast_hangup(), ast_indicate(), ast_log(), ast_parking_ext(), ast_party_connected_line_copy(), ast_party_connected_line_free(), ast_party_connected_line_init(), ast_read(), ast_safe_sleep(), ast_set_flag, AST_STATE_DOWN, AST_STATE_UP, ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_waitfordigit(), atxfercallbackretries, atxferdropcall, atxferloopdelay, atxfernoanswertimeout, ast_bridge_thread_obj::bconfig, bridge_call_thread_launch(), builtin_parkcall(), ast_bridge_thread_obj::chan, check_compat(), ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::connected, ast_channel::context, ast_datastore::data, ast_bridge_config::end_bridge_callback_data_fixup, ast_channel::exten, f, feature_request_and_dial(), ast_bridge_config::features_callee, ast_dial_features::features_caller, ast_bridge_config::features_caller, finishup(), ast_channel::language, ast_channel::linkedid, LOG_NOTICE, LOG_WARNING, ast_channel::name, ast_channel::nativeformats, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), ast_bridge_thread_obj::peer, ast_channel::priority, ast_channel::readformat, real_ctx(), set_peers(), ast_party_connected_line::source, strsep(), transferdigittimeout, ast_channel::visible_indication, ast_channel::writeformat, xferfailsound, and xfersound.
01514 { 01515 struct ast_channel *transferer; 01516 struct ast_channel *transferee; 01517 const char *transferer_real_context; 01518 char xferto[256] = ""; 01519 int res; 01520 int outstate=0; 01521 struct ast_channel *newchan; 01522 struct ast_channel *xferchan; 01523 struct ast_bridge_thread_obj *tobj; 01524 struct ast_bridge_config bconfig; 01525 struct ast_frame *f; 01526 int l; 01527 struct ast_party_connected_line connected_line; 01528 struct ast_datastore *features_datastore; 01529 struct ast_dial_features *dialfeatures = NULL; 01530 01531 ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense); 01532 set_peers(&transferer, &transferee, peer, chan, sense); 01533 transferer_real_context = real_ctx(transferer, transferee); 01534 /* Start autoservice on chan while we talk to the originator */ 01535 ast_autoservice_start(transferee); 01536 ast_indicate(transferee, AST_CONTROL_HOLD); 01537 01538 /* Transfer */ 01539 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY); 01540 if (res < 0) { 01541 finishup(transferee); 01542 return res; 01543 } 01544 if (res > 0) /* If they've typed a digit already, handle it */ 01545 xferto[0] = (char) res; 01546 01547 /* this is specific of atxfer */ 01548 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 01549 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */ 01550 finishup(transferee); 01551 return res; 01552 } 01553 if (res == 0) { 01554 ast_log(LOG_WARNING, "Did not read data.\n"); 01555 finishup(transferee); 01556 if (ast_stream_and_wait(transferer, "beeperr", "")) 01557 return -1; 01558 return AST_FEATURE_RETURN_SUCCESS; 01559 } 01560 01561 /* valid extension, res == 1 */ 01562 if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) { 01563 ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context); 01564 finishup(transferee); 01565 if (ast_stream_and_wait(transferer, "beeperr", "")) 01566 return -1; 01567 return AST_FEATURE_RETURN_SUCCESS; 01568 } 01569 01570 /* If we are attended transfering to parking, just use builtin_parkcall instead of trying to track all of 01571 * the different variables for handling this properly with a builtin_atxfer */ 01572 if (!strcmp(xferto, ast_parking_ext())) { 01573 finishup(transferee); 01574 return builtin_parkcall(chan, peer, config, code, sense, data); 01575 } 01576 01577 l = strlen(xferto); 01578 snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); /* append context */ 01579 01580 /* If we are performing an attended transfer and we have two channels involved then 01581 copy sound file information to play upon attended transfer completion */ 01582 if (transferee) { 01583 const char *chan1_attended_sound = pbx_builtin_getvar_helper(transferer, "ATTENDED_TRANSFER_COMPLETE_SOUND"); 01584 const char *chan2_attended_sound = pbx_builtin_getvar_helper(transferee, "ATTENDED_TRANSFER_COMPLETE_SOUND"); 01585 01586 if (!ast_strlen_zero(chan1_attended_sound)) { 01587 pbx_builtin_setvar_helper(transferer, "BRIDGE_PLAY_SOUND", chan1_attended_sound); 01588 } 01589 if (!ast_strlen_zero(chan2_attended_sound)) { 01590 pbx_builtin_setvar_helper(transferee, "BRIDGE_PLAY_SOUND", chan2_attended_sound); 01591 } 01592 } 01593 01594 newchan = feature_request_and_dial(transferer, transferee, "Local", ast_best_codec(transferer->nativeformats), 01595 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 1, transferer->language); 01596 01597 ast_party_connected_line_init(&connected_line); 01598 if (!ast_check_hangup(transferer)) { 01599 /* Transferer is up - old behaviour */ 01600 ast_indicate(transferer, -1); 01601 if (!newchan) { 01602 finishup(transferee); 01603 /* any reason besides user requested cancel and busy triggers the failed sound */ 01604 if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY && 01605 ast_stream_and_wait(transferer, xferfailsound, "")) 01606 return -1; 01607 if (ast_stream_and_wait(transferer, xfersound, "")) 01608 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 01609 return AST_FEATURE_RETURN_SUCCESS; 01610 } 01611 01612 if (check_compat(transferer, newchan)) { 01613 /* we do mean transferee here, NOT transferer */ 01614 finishup(transferee); 01615 return -1; 01616 } 01617 memset(&bconfig,0,sizeof(struct ast_bridge_config)); 01618 ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); 01619 ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); 01620 /* We need to get the transferer's connected line information copied 01621 * at this point because he is likely to hang up during the bridge with 01622 * newchan. This info will be used down below before bridging the 01623 * transferee and newchan 01624 * 01625 * As a result, we need to be sure to free this data before returning 01626 * or overwriting it. 01627 */ 01628 ast_channel_lock(transferer); 01629 ast_party_connected_line_copy(&connected_line, &transferer->connected); 01630 ast_channel_unlock(transferer); 01631 res = ast_bridge_call(transferer, newchan, &bconfig); 01632 if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) { 01633 ast_hangup(newchan); 01634 if (ast_stream_and_wait(transferer, xfersound, "")) 01635 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 01636 finishup(transferee); 01637 transferer->_softhangup = 0; 01638 ast_party_connected_line_free(&connected_line); 01639 return AST_FEATURE_RETURN_SUCCESS; 01640 } 01641 01642 ast_cel_report_event(transferee, AST_CEL_ATTENDEDTRANSFER, NULL, NULL, newchan); 01643 01644 if (check_compat(transferee, newchan)) { 01645 finishup(transferee); 01646 ast_party_connected_line_free(&connected_line); 01647 return -1; 01648 } 01649 ast_indicate(transferee, AST_CONTROL_UNHOLD); 01650 01651 if ((ast_autoservice_stop(transferee) < 0) 01652 || (ast_waitfordigit(transferee, 100) < 0) 01653 || (ast_waitfordigit(newchan, 100) < 0) 01654 || ast_check_hangup(transferee) 01655 || ast_check_hangup(newchan)) { 01656 ast_hangup(newchan); 01657 ast_party_connected_line_free(&connected_line); 01658 return -1; 01659 } 01660 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", transferee->linkedid, 0, "Transfered/%s", transferee->name); 01661 if (!xferchan) { 01662 ast_hangup(newchan); 01663 ast_party_connected_line_free(&connected_line); 01664 return -1; 01665 } 01666 /* Make formats okay */ 01667 xferchan->visible_indication = transferer->visible_indication; 01668 xferchan->readformat = transferee->readformat; 01669 xferchan->writeformat = transferee->writeformat; 01670 ast_channel_masquerade(xferchan, transferee); 01671 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority); 01672 xferchan->_state = AST_STATE_UP; 01673 ast_clear_flag(xferchan, AST_FLAGS_ALL); 01674 xferchan->_softhangup = 0; 01675 if ((f = ast_read(xferchan))) 01676 ast_frfree(f); 01677 newchan->_state = AST_STATE_UP; 01678 ast_clear_flag(newchan, AST_FLAGS_ALL); 01679 newchan->_softhangup = 0; 01680 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) { 01681 ast_hangup(xferchan); 01682 ast_hangup(newchan); 01683 ast_party_connected_line_free(&connected_line); 01684 return -1; 01685 } 01686 01687 ast_channel_lock(newchan); 01688 if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) { 01689 dialfeatures = features_datastore->data; 01690 } 01691 ast_channel_unlock(newchan); 01692 01693 if (dialfeatures) { 01694 /* newchan should always be the callee and shows up as callee in dialfeatures, but for some reason 01695 I don't currently understand, the abilities of newchan seem to be stored on the caller side */ 01696 ast_copy_flags(&(config->features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL); 01697 dialfeatures = NULL; 01698 } 01699 01700 ast_channel_lock(xferchan); 01701 if ((features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL))) { 01702 dialfeatures = features_datastore->data; 01703 } 01704 ast_channel_unlock(xferchan); 01705 01706 if (dialfeatures) { 01707 ast_copy_flags(&(config->features_caller), &(dialfeatures->features_caller), AST_FLAGS_ALL); 01708 } 01709 01710 tobj->chan = newchan; 01711 tobj->peer = xferchan; 01712 tobj->bconfig = *config; 01713 01714 if (tobj->bconfig.end_bridge_callback_data_fixup) { 01715 tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan); 01716 } 01717 01718 /* Due to a limitation regarding when callerID is set on a Local channel, 01719 * we use the transferer's connected line information here. 01720 */ 01721 01722 /* xferchan is transferee, and newchan is the transfer target 01723 * So...in a transfer, who is the caller and who is the callee? 01724 * 01725 * When the call is originally made, it is clear who is caller and callee. 01726 * When a transfer occurs, it is my humble opinion that the transferee becomes 01727 * the caller, and the transfer target is the callee. 01728 * 01729 * The problem is that these macros were set with the intention of the original 01730 * caller and callee taking those roles. A transfer can totally mess things up, 01731 * to be technical. What sucks even more is that you can't effectively change 01732 * the macros in the dialplan during the call from the transferer to the transfer 01733 * target because the transferee is stuck with whatever role he originally had. 01734 * 01735 * I think the answer here is just to make sure that it is well documented that 01736 * during a transfer, the transferee is the "caller" and the transfer target 01737 * is the "callee." 01738 * 01739 * This means that if party A calls party B, and party A transfers party B to 01740 * party C, then B has switched roles for the call. Now party B will have the 01741 * caller macro called on his channel instead of the callee macro. 01742 * 01743 * Luckily, the method by which the bridge is launched here ensures that the 01744 * transferee is the "chan" on the bridge and the transfer target is the "peer," 01745 * so my idea for the roles post-transfer does not require extensive code changes. 01746 */ 01747 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; 01748 if (ast_channel_connected_line_macro(newchan, xferchan, &connected_line, 1, 0)) { 01749 ast_channel_update_connected_line(xferchan, &connected_line); 01750 } 01751 ast_channel_lock(xferchan); 01752 ast_connected_line_copy_from_caller(&connected_line, &xferchan->cid); 01753 ast_channel_unlock(xferchan); 01754 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; 01755 if (ast_channel_connected_line_macro(xferchan, newchan, &connected_line, 0, 0)) { 01756 ast_channel_update_connected_line(newchan, &connected_line); 01757 } 01758 ast_party_connected_line_free(&connected_line); 01759 01760 if (ast_stream_and_wait(newchan, xfersound, "")) 01761 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 01762 bridge_call_thread_launch(tobj); 01763 return -1; /* XXX meaning the channel is bridged ? */ 01764 } else if (!ast_check_hangup(transferee)) { 01765 /* act as blind transfer */ 01766 if (ast_autoservice_stop(transferee) < 0) { 01767 ast_hangup(newchan); 01768 return -1; 01769 } 01770 01771 if (!newchan) { 01772 unsigned int tries = 0; 01773 char *transferer_tech, *transferer_name = ast_strdupa(transferer->name); 01774 01775 transferer_tech = strsep(&transferer_name, "/"); 01776 transferer_name = strsep(&transferer_name, "-"); 01777 01778 if (ast_strlen_zero(transferer_name) || ast_strlen_zero(transferer_tech)) { 01779 ast_log(LOG_WARNING, "Transferer has invalid channel name: '%s'\n", transferer->name); 01780 if (ast_stream_and_wait(transferee, "beeperr", "")) 01781 return -1; 01782 return AST_FEATURE_RETURN_SUCCESS; 01783 } 01784 01785 ast_log(LOG_NOTICE, "We're trying to call %s/%s\n", transferer_tech, transferer_name); 01786 newchan = feature_request_and_dial(transferee, NULL, transferer_tech, ast_best_codec(transferee->nativeformats), 01787 transferer_name, atxfernoanswertimeout, &outstate, transferee->cid.cid_num, transferee->cid.cid_name, 0, transferer->language); 01788 while (!newchan && !atxferdropcall && tries < atxfercallbackretries) { 01789 /* Trying to transfer again */ 01790 ast_autoservice_start(transferee); 01791 ast_indicate(transferee, AST_CONTROL_HOLD); 01792 01793 newchan = feature_request_and_dial(transferer, transferee, "Local", ast_best_codec(transferer->nativeformats), 01794 xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 1, transferer->language); 01795 if (ast_autoservice_stop(transferee) < 0) { 01796 if (newchan) 01797 ast_hangup(newchan); 01798 return -1; 01799 } 01800 if (!newchan) { 01801 /* Transfer failed, sleeping */ 01802 ast_debug(1, "Sleeping for %d ms before callback.\n", atxferloopdelay); 01803 ast_safe_sleep(transferee, atxferloopdelay); 01804 ast_debug(1, "Trying to callback...\n"); 01805 newchan = feature_request_and_dial(transferee, NULL, transferer_tech, ast_best_codec(transferee->nativeformats), 01806 transferer_name, atxfernoanswertimeout, &outstate, transferee->cid.cid_num, transferee->cid.cid_name, 0, transferer->language); 01807 } 01808 tries++; 01809 } 01810 } 01811 if (!newchan) 01812 return -1; 01813 01814 ast_cel_report_event(transferee, AST_CEL_ATTENDEDTRANSFER, NULL, NULL, newchan); 01815 01816 /* newchan is up, we should prepare transferee and bridge them */ 01817 if (check_compat(transferee, newchan)) { 01818 finishup(transferee); 01819 return -1; 01820 } 01821 ast_indicate(transferee, AST_CONTROL_UNHOLD); 01822 01823 if ((ast_waitfordigit(transferee, 100) < 0) 01824 || (ast_waitfordigit(newchan, 100) < 0) 01825 || ast_check_hangup(transferee) 01826 || ast_check_hangup(newchan)) { 01827 ast_hangup(newchan); 01828 return -1; 01829 } 01830 01831 xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", transferee->linkedid, 0, "Transfered/%s", transferee->name); 01832 if (!xferchan) { 01833 ast_hangup(newchan); 01834 return -1; 01835 } 01836 /* Make formats okay */ 01837 xferchan->visible_indication = transferer->visible_indication; 01838 xferchan->readformat = transferee->readformat; 01839 xferchan->writeformat = transferee->writeformat; 01840 ast_channel_masquerade(xferchan, transferee); 01841 ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority); 01842 xferchan->_state = AST_STATE_UP; 01843 ast_clear_flag(xferchan, AST_FLAGS_ALL); 01844 xferchan->_softhangup = 0; 01845 if ((f = ast_read(xferchan))) 01846 ast_frfree(f); 01847 newchan->_state = AST_STATE_UP; 01848 ast_clear_flag(newchan, AST_FLAGS_ALL); 01849 newchan->_softhangup = 0; 01850 if (!(tobj = ast_calloc(1, sizeof(*tobj)))) { 01851 ast_hangup(xferchan); 01852 ast_hangup(newchan); 01853 return -1; 01854 } 01855 tobj->chan = newchan; 01856 tobj->peer = xferchan; 01857 tobj->bconfig = *config; 01858 01859 if (tobj->bconfig.end_bridge_callback_data_fixup) { 01860 tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan); 01861 } 01862 01863 ast_channel_lock(newchan); 01864 ast_connected_line_copy_from_caller(&connected_line, &newchan->cid); 01865 ast_channel_unlock(newchan); 01866 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; 01867 if (ast_channel_connected_line_macro(newchan, xferchan, &connected_line, 1, 0)) { 01868 ast_channel_update_connected_line(xferchan, &connected_line); 01869 } 01870 ast_channel_lock(xferchan); 01871 ast_connected_line_copy_from_caller(&connected_line, &xferchan->cid); 01872 ast_channel_unlock(xferchan); 01873 connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; 01874 if (ast_channel_connected_line_macro(xferchan, newchan, &connected_line, 0, 0)) { 01875 ast_channel_update_connected_line(newchan, &connected_line); 01876 } 01877 01878 ast_party_connected_line_free(&connected_line); 01879 01880 if (ast_stream_and_wait(newchan, xfersound, "")) 01881 ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); 01882 bridge_call_thread_launch(tobj); 01883 return -1; /* XXX meaning the channel is bridged ? */ 01884 } else { 01885 /* Transferee hung up */ 01886 finishup(transferee); 01887 return -1; 01888 } 01889 }
| static int builtin_automixmonitor | ( | struct ast_channel * | chan, | |
| struct ast_channel * | peer, | |||
| struct ast_bridge_config * | config, | |||
| const char * | code, | |||
| int | sense, | |||
| void * | data | |||
| ) | [static] |
Definition at line 1218 of file features.c.
References AST_AUDIOHOOK_TYPE_SPY, ast_autoservice_start(), ast_autoservice_stop(), ast_channel_audiohook_count_by_source(), ast_channel_audiohook_count_by_source_running(), ast_channel_lock, ast_channel_unlock, AST_FEATURE_RETURN_SUCCESS, ast_log(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_verb, ast_channel::cid, ast_callerid::cid_num, courtesytone, len(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, mixmonitor_app, mixmonitor_ok, mixmonitor_spy_type, ast_channel::name, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), S_OR, set_peers(), stopmixmonitor_app, and stopmixmonitor_ok.
01219 { 01220 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 01221 int x = 0; 01222 size_t len; 01223 struct ast_channel *caller_chan, *callee_chan; 01224 const char *mixmonitor_spy_type = "MixMonitor"; 01225 int count = 0; 01226 01227 if (!mixmonitor_ok) { 01228 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n"); 01229 return -1; 01230 } 01231 01232 if (!(mixmonitor_app = pbx_findapp("MixMonitor"))) { 01233 mixmonitor_ok = 0; 01234 ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n"); 01235 return -1; 01236 } 01237 01238 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 01239 01240 if (!ast_strlen_zero(courtesytone)) { 01241 if (ast_autoservice_start(callee_chan)) 01242 return -1; 01243 if (ast_stream_and_wait(caller_chan, courtesytone, "")) { 01244 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 01245 ast_autoservice_stop(callee_chan); 01246 return -1; 01247 } 01248 if (ast_autoservice_stop(callee_chan)) 01249 return -1; 01250 } 01251 01252 ast_channel_lock(callee_chan); 01253 count = ast_channel_audiohook_count_by_source(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY); 01254 ast_channel_unlock(callee_chan); 01255 01256 /* This means a mixmonitor is attached to the channel, running or not is unknown. */ 01257 if (count > 0) { 01258 01259 ast_verb(3, "User hit '%s' to stop recording call.\n", code); 01260 01261 /* Make sure they are running */ 01262 ast_channel_lock(callee_chan); 01263 count = ast_channel_audiohook_count_by_source_running(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY); 01264 ast_channel_unlock(callee_chan); 01265 if (count > 0) { 01266 if (!stopmixmonitor_ok) { 01267 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n"); 01268 return -1; 01269 } 01270 if (!(stopmixmonitor_app = pbx_findapp("StopMixMonitor"))) { 01271 stopmixmonitor_ok = 0; 01272 ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n"); 01273 return -1; 01274 } else { 01275 pbx_exec(callee_chan, stopmixmonitor_app, ""); 01276 return AST_FEATURE_RETURN_SUCCESS; 01277 } 01278 } 01279 01280 ast_log(LOG_WARNING,"Stopped MixMonitors are attached to the channel.\n"); 01281 } 01282 01283 if (caller_chan && callee_chan) { 01284 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR_FORMAT"); 01285 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR"); 01286 01287 if (!touch_format) 01288 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR_FORMAT"); 01289 01290 if (!touch_monitor) 01291 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR"); 01292 01293 if (touch_monitor) { 01294 len = strlen(touch_monitor) + 50; 01295 args = alloca(len); 01296 touch_filename = alloca(len); 01297 snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor); 01298 snprintf(args, len, "%s.%s,b", touch_filename, (touch_format) ? touch_format : "wav"); 01299 } else { 01300 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name)); 01301 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name)); 01302 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 01303 args = alloca(len); 01304 touch_filename = alloca(len); 01305 snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id); 01306 snprintf(args, len, "%s.%s,b", touch_filename, S_OR(touch_format, "wav")); 01307 } 01308 01309 for( x = 0; x < strlen(args); x++) { 01310 if (args[x] == '/') 01311 args[x] = '-'; 01312 } 01313 01314 ast_verb(3, "User hit '%s' to record call. filename: %s\n", code, touch_filename); 01315 01316 pbx_exec(callee_chan, mixmonitor_app, args); 01317 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename); 01318 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename); 01319 return AST_FEATURE_RETURN_SUCCESS; 01320 01321 } 01322 01323 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); 01324 return -1; 01325 01326 }
| static int builtin_automonitor | ( | struct ast_channel * | chan, | |
| struct ast_channel * | peer, | |||
| struct ast_bridge_config * | config, | |||
| const char * | code, | |||
| int | sense, | |||
| void * | data | |||
| ) | [static] |
Monitor a channel by DTMF.
| chan | channel requesting monitor | |
| peer | channel to be monitored | |
| config | ||
| code | ||
| sense | feature options | |
| data | Check monitor app enabled, setup channels, both caller/callee chans not null get TOUCH_MONITOR variable for filename if exists, exec monitor app. |
| AST_FEATURE_RETURN_SUCCESS | on success. | |
| -1 | on error. |
Definition at line 1125 of file features.c.
References AST_FEATURE_RETURN_SUCCESS, ast_log(), ast_strdupa, ast_strlen_zero(), ast_verb, ast_channel::cid, ast_callerid::cid_num, courtesytone, len(), LOG_ERROR, LOG_NOTICE, ast_channel::monitor, monitor_app, monitor_ok, ast_channel::name, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), play_message_in_bridged_call(), S_OR, set_peers(), and ast_channel_monitor::stop.
01126 { 01127 char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; 01128 int x = 0; 01129 size_t len; 01130 struct ast_channel *caller_chan, *callee_chan; 01131 const char *automon_message_start = NULL; 01132 const char *automon_message_stop = NULL; 01133 01134 if (!monitor_ok) { 01135 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 01136 return -1; 01137 } 01138 01139 if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) { 01140 monitor_ok = 0; 01141 ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); 01142 return -1; 01143 } 01144 01145 set_peers(&caller_chan, &callee_chan, peer, chan, sense); 01146 if (caller_chan) { /* Find extra messages */ 01147 automon_message_start = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_START"); 01148 automon_message_stop = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_STOP"); 01149 } 01150 01151 if (!ast_strlen_zero(courtesytone)) { /* Play courtesy tone if configured */ 01152 if(play_message_in_bridged_call(caller_chan, callee_chan, courtesytone) == -1) { 01153 return -1; 01154 } 01155 } 01156 01157 if (callee_chan->monitor) { 01158 ast_verb(4, "User hit '%s' to stop recording call.\n", code); 01159 if (!ast_strlen_zero(automon_message_stop)) { 01160 play_message_in_bridged_call(caller_chan, callee_chan, automon_message_stop); 01161 } 01162 callee_chan->monitor->stop(callee_chan, 1); 01163 return AST_FEATURE_RETURN_SUCCESS; 01164 } 01165 01166 if (caller_chan && callee_chan) { 01167 const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT"); 01168 const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR"); 01169 const char *touch_monitor_prefix = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_PREFIX"); 01170 01171 if (!touch_format) 01172 touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT"); 01173 01174 if (!touch_monitor) 01175 touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR"); 01176 01177 if (!touch_monitor_prefix) 01178 touch_monitor_prefix = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_PREFIX"); 01179 01180 if (touch_monitor) { 01181 len = strlen(touch_monitor) + 50; 01182 args = alloca(len); 01183 touch_filename = alloca(len); 01184 snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor); 01185 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename); 01186 } else { 01187 caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name)); 01188 callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name)); 01189 len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; 01190 args = alloca(len); 01191 touch_filename = alloca(len); 01192 snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, callee_chan_id); 01193 snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename); 01194 } 01195 01196 for(x = 0; x < strlen(args); x++) { 01197 if (args[x] == '/') 01198 args[x] = '-'; 01199 } 01200 01201 ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args); 01202 01203 pbx_exec(callee_chan, monitor_app, args); 01204 pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 01205 pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); 01206 01207 if (!ast_strlen_zero(automon_message_start)) { /* Play start message for both channels */ 01208 play_message_in_bridged_call(caller_chan, callee_chan, automon_message_start); 01209 } 01210 01211 return AST_FEATURE_RETURN_SUCCESS; 01212 } 01213 01214 ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); 01215 return -1; 01216 }
| static int builtin_blindtransfer | ( | struct ast_channel * | chan, | |
| struct ast_channel * | peer, | |||
| struct ast_bridge_config * | config, | |||
| const char * | code, | |||
| int | sense, | |||
| void * | data | |||
| ) | [static] |
Blind transfer user to another extension.
| chan | channel to be transfered | |
| peer | channel initiated blind transfer | |
| config | ||
| code | ||
| data | ||
| sense | feature options |
| AST_FEATURE_RETURN_SUCCESS. | ||
| -1 | on failure. |
Definition at line 1378 of file features.c.
References ast_app_dtget(), ast_async_goto(), ast_autoservice_start(), ast_cdr_alloc(), ast_cdr_init(), ast_cdr_start(), AST_CEL_BLINDTRANSFER, ast_cel_report_event(), ast_channel_connected_line_macro(), ast_channel_update_connected_line(), AST_CONTROL_HOLD, AST_DIGIT_ANY, ast_exists_extension(), AST_FEATURE_RETURN_PARKFAILED, AST_FEATURE_RETURN_SUCCESS, AST_FLAG_BRIDGE_HANGUP_DONT, ast_indicate(), ast_log(), ast_parking_ext(), ast_set_flag, ast_stopstream(), ast_stream_and_wait(), ast_verb, ast_channel::cdr, ast_cdr::channel, check_goto_on_transfer(), ast_channel::cid, ast_callerid::cid_num, ast_channel::connected, ast_cdr::dstchannel, finishup(), ast_cdr::lastapp, ast_cdr::lastdata, LOG_DEBUG, LOG_WARNING, masq_park_call_announce(), ast_channel::name, ast_channel::pbx, pbx_builtin_setvar_helper(), real_ctx(), set_c_e_p(), set_peers(), transferdigittimeout, and xferfailsound.
01379 { 01380 struct ast_channel *transferer; 01381 struct ast_channel *transferee; 01382 const char *transferer_real_context; 01383 char xferto[256]; 01384 int res, parkstatus = 0; 01385 01386 set_peers(&transferer, &transferee, peer, chan, sense); 01387 transferer_real_context = real_ctx(transferer, transferee); 01388 /* Start autoservice on chan while we talk to the originator */ 01389 ast_autoservice_start(transferee); 01390 ast_indicate(transferee, AST_CONTROL_HOLD); 01391 01392 memset(xferto, 0, sizeof(xferto)); 01393 01394 /* Transfer */ 01395 res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY); 01396 if (res < 0) { 01397 finishup(transferee); 01398 return -1; /* error ? */ 01399 } 01400 if (res > 0) /* If they've typed a digit already, handle it */ 01401 xferto[0] = (char) res; 01402 01403 ast_stopstream(transferer); 01404 res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout); 01405 if (res < 0) { /* hangup, would be 0 for invalid and 1 for valid */ 01406 finishup(transferee); 01407 return res; 01408 } 01409 if (!strcmp(xferto, ast_parking_ext())) { 01410 res = finishup(transferee); 01411 if (res) 01412 res = -1; 01413 else if (!(parkstatus = masq_park_call_announce(transferee, transferer, 0, NULL))) { /* success */ 01414 /* We return non-zero, but tell the PBX not to hang the channel when 01415 the thread dies -- We have to be careful now though. We are responsible for 01416 hanging up the channel, else it will never be hung up! */ 01417 01418 return 0; 01419 } else { 01420 ast_log(LOG_WARNING, "Unable to park call %s, parkstatus = %d\n", transferee->name, parkstatus); 01421 } 01422 /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */ 01423 } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) { 01424 ast_cel_report_event(transferer, AST_CEL_BLINDTRANSFER, NULL, xferto, transferee); 01425 pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name); 01426 pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name); 01427 res=finishup(transferee); 01428 if (!transferer->cdr) { /* this code should never get called (in a perfect world) */ 01429 transferer->cdr=ast_cdr_alloc(); 01430 if (transferer->cdr) { 01431 ast_cdr_init(transferer->cdr, transferer); /* initialize our channel's cdr */ 01432 ast_cdr_start(transferer->cdr); 01433 } 01434 } 01435 if (transferer->cdr) { 01436 struct ast_cdr *swap = transferer->cdr; 01437 ast_log(LOG_DEBUG,"transferer=%s; transferee=%s; lastapp=%s; lastdata=%s; chan=%s; dstchan=%s\n", 01438 transferer->name, transferee->name, transferer->cdr->lastapp, transferer->cdr->lastdata, 01439 transferer->cdr->channel, transferer->cdr->dstchannel); 01440 ast_log(LOG_DEBUG,"TRANSFEREE; lastapp=%s; lastdata=%s, chan=%s; dstchan=%s\n", 01441 transferee->cdr->lastapp, transferee->cdr->lastdata, transferee->cdr->channel, transferee->cdr->dstchannel); 01442 ast_log(LOG_DEBUG,"transferer_real_context=%s; xferto=%s\n", transferer_real_context, xferto); 01443 /* swap cdrs-- it will save us some time & work */ 01444 transferer->cdr = transferee->cdr; 01445 transferee->cdr = swap; 01446 } 01447 if (!transferee->pbx) { 01448 /* Doh! Use our handy async_goto functions */ 01449 ast_verb(3, "Transferring %s to '%s' (context %s) priority 1\n" 01450 ,transferee->name, xferto, transferer_real_context); 01451 if (ast_async_goto(transferee, transferer_real_context, xferto, 1)) 01452 ast_log(LOG_WARNING, "Async goto failed :-(\n"); 01453 } else { 01454 /* Set the channel's new extension, since it exists, using transferer context */ 01455 ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */ 01456 ast_log(LOG_DEBUG,"ABOUT TO AST_ASYNC_GOTO, have a pbx... set HANGUP_DONT on chan=%s\n", transferee->name); 01457 if (ast_channel_connected_line_macro(transferee, transferer, &transferer->connected, 1, 0)) { 01458 ast_channel_update_connected_line(transferee, &transferer->connected); 01459 } 01460 set_c_e_p(transferee, transferer_real_context, xferto, 0); 01461 } 01462 check_goto_on_transfer(transferer); 01463 return res; 01464 } else { 01465 ast_verb(3, "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context); 01466 } 01467 if (parkstatus != AST_FEATURE_RETURN_PARKFAILED && ast_stream_and_wait(transferer, xferfailsound, AST_DIGIT_ANY) < 0) { 01468 finishup(transferee); 01469 return -1; 01470 } 01471 ast_stopstream(transferer); 01472 res = finishup(transferee); 01473 if (res) { 01474 ast_verb(2, "Hungup during autoservice stop on '%s'\n", transferee->name); 01475 return res; 01476 } 01477 return AST_FEATURE_RETURN_SUCCESS; 01478 }
| static int builtin_disconnect | ( | struct ast_channel * | chan, | |
| struct ast_channel * | peer, | |||
| struct ast_bridge_config * | config, | |||
| const char * | code, | |||
| int | sense, | |||
| void * | data | |||
| ) | [static] |
Definition at line 1328 of file features.c.
References AST_FEATURE_RETURN_HANGUP, and ast_verb.
01329 { 01330 ast_verb(4, "User hit '%s' to disconnect call.\n", code); 01331 return AST_FEATURE_RETURN_HANGUP; 01332 }
| static int builtin_parkcall | ( | struct ast_channel * | chan, | |
| struct ast_channel * | peer, | |||
| struct ast_bridge_config * | config, | |||
| const char * | code, | |||
| int | sense, | |||
| void * | data | |||
| ) | [static] |
support routing for one touch call parking
| chan | channel parking call | |
| peer | channel to be parked | |
| config | unsed | |
| code | unused | |
| sense | feature options | |
| data | Setup channel, set return exten,priority to 's,1' answer chan, sleep chan, park call |
Definition at line 1055 of file features.c.
References ast_channel::_state, ast_answer(), ast_safe_sleep(), AST_STATE_UP, masq_park_call_announce(), and set_peers().
Referenced by builtin_atxfer().
01056 { 01057 struct ast_channel *parker; 01058 struct ast_channel *parkee; 01059 int res = 0; 01060 01061 set_peers(&parker, &parkee, peer, chan, sense); 01062 /* we used to set chan's exten and priority to "s" and 1 01063 here, but this generates (in some cases) an invalid 01064 extension, and if "s" exists, could errantly 01065 cause execution of extensions you don't expect. It 01066 makes more sense to let nature take its course 01067 when chan finishes, and let the pbx do its thing 01068 and hang up when the park is over. 01069 */ 01070 if (chan->_state != AST_STATE_UP) 01071 res = ast_answer(chan); 01072 if (!res) 01073 res = ast_safe_sleep(chan, 1000); 01074 01075 if (!res) { /* one direction used to call park_call.... */ 01076 res = masq_park_call_announce(parkee, parker, 0, NULL); 01077 /* PBX should hangup zombie channel if a masquerade actually occurred (res=0) */ 01078 } 01079 01080 return res; 01081 }
| static char* callback_dialoptions | ( | struct ast_flags * | features_callee, | |
| struct ast_flags * | features_caller, | |||
| char * | options, | |||
| size_t | len | |||
| ) | [static] |
Definition at line 3229 of file features.c.
References AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, and ast_test_flag.
Referenced by manage_parkinglot().
03230 { 03231 int i = 0; 03232 enum { 03233 OPT_CALLEE_REDIRECT = 't', 03234 OPT_CALLER_REDIRECT = 'T', 03235 OPT_CALLEE_AUTOMON = 'w', 03236 OPT_CALLER_AUTOMON = 'W', 03237 OPT_CALLEE_DISCONNECT = 'h', 03238 OPT_CALLER_DISCONNECT = 'H', 03239 OPT_CALLEE_PARKCALL = 'k', 03240 OPT_CALLER_PARKCALL = 'K', 03241 }; 03242 03243 memset(options, 0, len); 03244 if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) { 03245 options[i++] = OPT_CALLER_REDIRECT; 03246 } 03247 if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) { 03248 options[i++] = OPT_CALLER_AUTOMON; 03249 } 03250 if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) { 03251 options[i++] = OPT_CALLER_DISCONNECT; 03252 } 03253 if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) { 03254 options[i++] = OPT_CALLER_PARKCALL; 03255 } 03256 03257 if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) { 03258 options[i++] = OPT_CALLEE_REDIRECT; 03259 } 03260 if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) { 03261 options[i++] = OPT_CALLEE_AUTOMON; 03262 } 03263 if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) { 03264 options[i++] = OPT_CALLEE_DISCONNECT; 03265 } 03266 if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) { 03267 options[i++] = OPT_CALLEE_PARKCALL; 03268 } 03269 03270 return options; 03271 }
| static int check_compat | ( | struct ast_channel * | c, | |
| struct ast_channel * | newchan | |||
| ) | [static] |
make channels compatible
| c | ||
| newchan |
| 0 | on success. | |
| -1 | on failure. |
Definition at line 1487 of file features.c.
References ast_channel_make_compatible(), ast_hangup(), ast_log(), LOG_WARNING, and ast_channel::name.
Referenced by builtin_atxfer().
01488 { 01489 if (ast_channel_make_compatible(c, newchan) < 0) { 01490 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", 01491 c->name, newchan->name); 01492 ast_hangup(newchan); 01493 return -1; 01494 } 01495 return 0; 01496 }
| static void check_goto_on_transfer | ( | struct ast_channel * | chan | ) | [static] |
Check goto on transfer.
| chan | Check if channel has 'GOTO_ON_BLINDXFR' set, if not exit. When found make sure the types are compatible. Check if channel is valid if so start the new channel else hangup the call. |
Definition at line 482 of file 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, ast_channel::linkedid, ast_channel::name, pbx_builtin_getvar_helper(), ast_channel::readformat, and ast_channel::writeformat.
Referenced by builtin_blindtransfer().
00483 { 00484 struct ast_channel *xferchan; 00485 const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR"); 00486 char *x, *goto_on_transfer; 00487 struct ast_frame *f; 00488 00489 if (ast_strlen_zero(val)) 00490 return; 00491 00492 goto_on_transfer = ast_strdupa(val); 00493 00494 if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", chan->linkedid, 0, "%s", chan->name))) 00495 return; 00496 00497 for (x = goto_on_transfer; x && *x; x++) { 00498 if (*x == '^') 00499 *x = '|'; 00500 } 00501 /* Make formats okay */ 00502 xferchan->readformat = chan->readformat; 00503 xferchan->writeformat = chan->writeformat; 00504 ast_channel_masquerade(xferchan, chan); 00505 ast_parseable_goto(xferchan, goto_on_transfer); 00506 xferchan->_state = AST_STATE_UP; 00507 ast_clear_flag(xferchan, AST_FLAGS_ALL); 00508 xferchan->_softhangup = 0; 00509 if ((f = ast_read(xferchan))) { 00510 ast_frfree(f); 00511 f = NULL; 00512 ast_pbx_start(xferchan); 00513 } else { 00514 ast_hangup(xferchan); 00515 } 00516 }
| static struct ast_parkinglot* create_parkinglot | ( | char * | name | ) | [static, read] |
Allocate parking lot structure.
Definition at line 3789 of file features.c.
References ao2_alloc, ast_copy_string(), AST_LIST_HEAD_INIT, ast_parkinglot::name, parkinglot_destroy(), and ast_parkinglot::parkings.
Referenced by build_parkinglot().
03790 { 03791 struct ast_parkinglot *newlot = (struct ast_parkinglot *) NULL; 03792 03793 if (!name) 03794 return NULL; 03795 03796 newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy); 03797 if (!newlot) 03798 return NULL; 03799 03800 ast_copy_string(newlot->name, name, sizeof(newlot->name)); 03801 AST_LIST_HEAD_INIT(&newlot->parkings); 03802 03803 return newlot; 03804 }
| static void dial_features_destroy | ( | void * | data | ) | [static] |
Definition at line 409 of file features.c.
References ast_free.
00410 { 00411 struct ast_dial_features *df = data; 00412 if (df) { 00413 ast_free(df); 00414 } 00415 }
| static void* dial_features_duplicate | ( | void * | data | ) | [static] |
Definition at line 396 of file features.c.
References ast_calloc.
00397 { 00398 struct ast_dial_features *df = data, *df_copy; 00399 00400 if (!(df_copy = ast_calloc(1, sizeof(*df)))) { 00401 return NULL; 00402 } 00403 00404 memcpy(df_copy, df, sizeof(*df)); 00405 00406 return df_copy; 00407 }
| static void do_bridge_masquerade | ( | struct ast_channel * | chan, | |
| struct ast_channel * | tmpchan | |||
| ) | [static] |
Actual bridge.
| chan | ||
| tmpchan | Stop hold music, lock both channels, masq channels, after bridge return channel to next priority. |
Definition at line 4382 of file features.c.
References ast_channel::_state, ast_channel_lock_both, ast_channel_masquerade(), ast_channel_unlock, ast_do_masquerade(), ast_explicit_goto(), ast_moh_stop(), ast_setstate(), ast_channel::context, ast_channel::exten, ast_channel::priority, ast_channel::readformat, and ast_channel::writeformat.
Referenced by action_bridge(), and bridge_exec().
04383 { 04384 ast_moh_stop(chan); 04385 ast_channel_lock_both(chan, tmpchan); 04386 ast_setstate(tmpchan, chan->_state); 04387 tmpchan->readformat = chan->readformat; 04388 tmpchan->writeformat = chan->writeformat; 04389 ast_channel_masquerade(tmpchan, chan); 04390 ast_channel_unlock(chan); 04391 ast_channel_unlock(tmpchan); 04392 04393 /* must be done without any channel locks held */ 04394 ast_do_masquerade(tmpchan); 04395 04396 /* when returning from bridge, the channel will continue at the next priority */ 04397 ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1); 04398 }
| static void* do_parking_thread | ( | void * | ignore | ) | [static] |
Take care of parked calls and unpark them if needed.
| ignore | unused var. |
Definition at line 3456 of file features.c.
References ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_samp2tv(), ast_select(), manage_parkinglot(), and parkinglots.
Referenced by ast_features_init().
03457 { 03458 fd_set rfds, efds; /* results from previous select, to be preserved across loops. */ 03459 fd_set nrfds, nefds; /* args for the next select */ 03460 FD_ZERO(&rfds); 03461 FD_ZERO(&efds); 03462 03463 for (;;) { 03464 int res = 0; 03465 int ms = -1; /* select timeout, uninitialized */ 03466 int max = -1; /* max fd, none there yet */ 03467 struct ao2_iterator iter; 03468 struct ast_parkinglot *curlot; 03469 FD_ZERO(&nrfds); 03470 FD_ZERO(&nefds); 03471 iter = ao2_iterator_init(parkinglots, 0); 03472 03473 while ((curlot = ao2_iterator_next(&iter))) { 03474 res = manage_parkinglot(curlot, &rfds, &efds, &nrfds, &nefds, &ms, &max); 03475 ao2_ref(curlot, -1); 03476 } 03477 03478 rfds = nrfds; 03479 efds = nefds; 03480 { 03481 struct timeval wait = ast_samp2tv(ms, 1000); 03482 /* Wait for something to happen */ 03483 ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &wait : NULL); 03484 } 03485 pthread_testcancel(); 03486 } 03487 return NULL; /* Never reached */ 03488 }
| static int feature_exec_app | ( | struct ast_channel * | chan, | |
| struct ast_channel * | peer, | |||
| struct ast_bridge_config * | config, | |||
| const char * | code, | |||
| int | sense, | |||
| void * | data | |||
| ) | [static] |
exec an app by feature
| chan,peer,config,code,sense,data | Find a feature, determine which channel activated |
| AST_FEATURE_RETURN_NO_HANGUP_PEER | ||
| -1 | error. | |
| -2 | when an application cannot be found. |
Definition at line 2101 of file 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_FEATURE_RETURN_KEEPTRYING, AST_FEATURE_RETURN_SUCCESS, AST_FEATURE_RETURN_SUCCESSBREAK, ast_log(), ast_moh_start(), ast_moh_stop(), ast_strlen_zero(), ast_test_flag, FEATURE_SENSE_CHAN, LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, ast_channel::name, pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), and ast_call_feature::sname.
Referenced by load_config().
02102 { 02103 struct ast_app *app; 02104 struct ast_call_feature *feature = data; 02105 struct ast_channel *work, *idle; 02106 int res; 02107 02108 if (!feature) { /* shouldn't ever happen! */ 02109 ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n"); 02110 return -1; 02111 } 02112 02113 if (sense == FEATURE_SENSE_CHAN) { 02114 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER)) 02115 return AST_FEATURE_RETURN_KEEPTRYING; 02116 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 02117 work = chan; 02118 idle = peer; 02119 } else { 02120 work = peer; 02121 idle = chan; 02122 } 02123 } else { 02124 if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE)) 02125 return AST_FEATURE_RETURN_KEEPTRYING; 02126 if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) { 02127 work = peer; 02128 idle = chan; 02129 } else { 02130 work = chan; 02131 idle = peer; 02132 } 02133 } 02134 02135 if (!(app = pbx_findapp(feature->app))) { 02136 ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app); 02137 return -2; 02138 } 02139 02140 ast_autoservice_start(idle); 02141 02142 if(work && idle) { 02143 pbx_builtin_setvar_helper(work, "DYNAMIC_PEERNAME", idle->name); 02144 pbx_builtin_setvar_helper(idle, "DYNAMIC_PEERNAME", work->name); 02145 pbx_builtin_setvar_helper(work, "DYNAMIC_FEATURENAME", feature->sname); 02146 pbx_builtin_setvar_helper(idle, "DYNAMIC_FEATURENAME", feature->sname); 02147 } 02148 02149 if (!ast_strlen_zero(feature->moh_class)) 02150 ast_moh_start(idle, feature->moh_class, NULL); 02151 02152 res = pbx_exec(work, app, feature->app_args); 02153 02154 if (!ast_strlen_zero(feature->moh_class)) 02155 ast_moh_stop(idle); 02156 02157 ast_autoservice_stop(idle); 02158 02159 if (res) { 02160 return AST_FEATURE_RETURN_SUCCESSBREAK; 02161 } 02162 return AST_FEATURE_RETURN_SUCCESS; /*! \todo XXX should probably return res */ 02163 }
| static int feature_interpret | ( | struct ast_channel * | chan, | |
| struct ast_channel * | peer, | |||
| struct ast_bridge_config * | config, | |||
| const char * | code, | |||
| int | sense | |||
| ) | [static] |
Check the dynamic features.
| chan,peer,config,code,sense |
| res | on success. | |
| -1 | on failure. |
Definition at line 2307 of file features.c.
References ast_channel_lock, ast_channel_unlock, ast_copy_flags, ast_debug, AST_FLAGS_ALL, ast_strdupa, feature_interpret_helper(), FEATURE_SENSE_CHAN, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_flags::flags, ast_channel::name, pbx_builtin_getvar_helper(), and S_OR.
Referenced by ast_bridge_call().
02307 { 02308 02309 char dynamic_features_buf[128]; 02310 const char *peer_dynamic_features, *chan_dynamic_features; 02311 struct ast_flags features; 02312 struct ast_call_feature feature; 02313 if (sense == FEATURE_SENSE_CHAN) { 02314 ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL); 02315 } 02316 else { 02317 ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL); 02318 } 02319 02320 ast_channel_lock(peer); 02321 peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),"")); 02322 ast_channel_unlock(peer); 02323 02324 ast_channel_lock(chan); 02325 chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),"")); 02326 ast_channel_unlock(chan); 02327 02328 snprintf(dynamic_features_buf, sizeof(dynamic_features_buf), "%s%s%s", S_OR(chan_dynamic_features, ""), chan_dynamic_features && peer_dynamic_features ? "#" : "", S_OR(peer_dynamic_features,"")); 02329 02330 ast_debug(3, "Feature interpret: chan=%s, peer=%s, code=%s, sense=%d, features=%d, dynamic=%s\n", chan->name, peer->name, code, sense, features.flags, dynamic_features_buf); 02331 02332 return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, 1, &feature); 02333 }
| static int feature_interpret_helper | ( | struct ast_channel * | chan, | |
| struct ast_channel * | peer, | |||
| struct ast_bridge_config * | config, | |||
| const char * | code, | |||
| int | sense, | |||
| char * | dynamic_features_buf, | |||
| struct ast_flags * | features, | |||
| int | operation, | |||
| struct ast_call_feature * | feature | |||
| ) | [static] |
Helper function for feature_interpret and ast_feature_detect.
| chan,peer,config,code,sense,dynamic_features | char buf,feature flags,operation,feature |
| res | on success. | |
| -1 | on failure. |
Definition at line 2203 of file features.c.
References ast_debug, AST_FEATURE_RETURN_KEEPTRYING, AST_FEATURE_RETURN_PASSDIGITS, AST_FEATURE_RETURN_STOREDIGITS, AST_LIST_TRAVERSE, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_strlen_zero(), ast_test_flag, ast_verb, ast_call_feature::exten, feature_group_exten::exten, feature_group_exten::feature, ast_call_feature::feature_mask, feature_group::features, FEATURES_COUNT, features_lock, find_dynamic_feature(), find_group(), ast_call_feature::fname, ast_call_feature::operation, ast_call_feature::sname, and strsep().
Referenced by ast_feature_detect(), and feature_interpret().
02206 { 02207 int x; 02208 struct feature_group *fg = NULL; 02209 struct feature_group_exten *fge; 02210 struct ast_call_feature *tmpfeature; 02211 char *tmp, *tok; 02212 int res = AST_FEATURE_RETURN_PASSDIGITS; 02213 int feature_detected = 0; 02214 02215 if (!(peer && chan && config) && operation) { 02216 return -1; /* can not run feature operation */ 02217 } 02218 02219 ast_rwlock_rdlock(&features_lock); 02220 for (x = 0; x < FEATURES_COUNT; x++) { 02221 if ((ast_test_flag(features, builtin_features[x].feature_mask)) && 02222 !ast_strlen_zero(builtin_features[x].exten)) { 02223 /* Feature is up for consideration */ 02224 if (!strcmp(builtin_features[x].exten, code)) { 02225 ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten); 02226 if (operation) { 02227 res = builtin_features[x].operation(chan, peer, config, code, sense, NULL); 02228 } 02229 memcpy(feature, &builtin_features[x], sizeof(feature)); 02230 feature_detected = 1; 02231 break; 02232 } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) { 02233 if (res == AST_FEATURE_RETURN_PASSDIGITS) 02234 res = AST_FEATURE_RETURN_STOREDIGITS; 02235 } 02236 } 02237 } 02238 ast_rwlock_unlock(&features_lock); 02239 02240 if (ast_strlen_zero(dynamic_features_buf) || feature_detected) { 02241 return res; 02242 } 02243 02244 tmp = dynamic_features_buf; 02245 02246 while ((tok = strsep(&tmp, "#"))) { 02247 AST_RWLIST_RDLOCK(&feature_groups); 02248 02249 fg = find_group(tok); 02250 02251 if (fg) { 02252 AST_LIST_TRAVERSE(&fg->features, fge, entry) { 02253 if (strcasecmp(fge->exten, code)) 02254 continue; 02255 if (operation) { 02256 res = fge->feature->operation(chan, peer, config, code, sense, fge->feature); 02257 } 02258 memcpy(feature, fge->feature, sizeof(feature)); 02259 if (res != AST_FEATURE_RETURN_KEEPTRYING) { 02260 AST_RWLIST_UNLOCK(&feature_groups); 02261 break; 02262 } 02263 res = AST_FEATURE_RETURN_PASSDIGITS; 02264 } 02265 if (fge) 02266 break; 02267 } 02268 02269 AST_RWLIST_UNLOCK(&feature_groups); 02270 02271 AST_RWLIST_RDLOCK(&feature_list); 02272 02273 if (!(tmpfeature = find_dynamic_feature(tok))) { 02274 AST_RWLIST_UNLOCK(&feature_list); 02275 continue; 02276 } 02277 02278 /* Feature is up for consideration */ 02279 if (!strcmp(tmpfeature->exten, code)) { 02280 ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok); 02281 if (operation) { 02282 res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature); 02283 } 02284 memcpy(feature, tmpfeature, sizeof(feature)); 02285 if (res != AST_FEATURE_RETURN_KEEPTRYING) { 02286 AST_RWLIST_UNLOCK(&feature_list); 02287 break; 02288 } 02289 res = AST_FEATURE_RETURN_PASSDIGITS; 02290 } else if (!strncmp(tmpfeature->exten, code, strlen(code))) 02291 res = AST_FEATURE_RETURN_STOREDIGITS; 02292 02293 AST_RWLIST_UNLOCK(&feature_list); 02294 } 02295 02296 return res; 02297 }
| static struct ast_channel * feature_request_and_dial | ( | struct ast_channel * | caller, | |
| struct ast_channel * | transferee, | |||
| const char * | type, | |||
| int | format, | |||
| void * | data, | |||
| int | timeout, | |||
| int * | outstate, | |||
| const char * | cid_num, | |||
| const char * | cid_name, | |||
| int | igncallerstate, | |||
| const char * | language | |||
| ) | [static, read] |
Get feature and dial.
| caller,transferee,type,format,data,timeout,outstate,cid_num,cid_name,igncallerstate | Request channel, set channel variables, initiate call,check if they want to disconnect go into loop, check if timeout has elapsed, check if person to be transfered hung up, check for answer break loop, set cdr return channel. |
Definition at line 2394 of file features.c.
References ast_channel::_state, ast_call(), ast_call_forward(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, ast_channel_connected_line_macro(), ast_channel_inherit_variables(), ast_channel_lock, ast_channel_unlock, ast_check_hangup(), ast_connected_line_copy_from_caller(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_CONNECTED_LINE, AST_CONTROL_HANGUP, AST_CONTROL_PROGRESS, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_TEXT, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_hangup(), ast_indicate(), ast_indicate_data(), ast_log(), ast_poll_channel_add(), ast_poll_channel_del(), ast_read(), ast_request(), ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_set_callerid(), AST_STATE_UP, ast_string_field_set, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_waitfor_n(), ast_write(), ast_channel::call_forward, cause, ast_channel::cid, ast_channel::connected, ast_frame::data, ast_frame::datalen, ast_call_feature::exten, f, FEATURES_COUNT, features_lock, ast_frame::frametype, len(), LOG_NOTICE, ast_channel::name, pbx_builtin_setvar_helper(), ast_frame::ptr, and ast_frame::subclass.
Referenced by builtin_atxfer().
02395 { 02396 int state = 0; 02397 int cause = 0; 02398 int to; 02399 struct ast_channel *chan; 02400 struct ast_channel *monitor_chans[2]; 02401 struct ast_channel *active_channel; 02402 int res = 0, ready = 0; 02403 struct timeval started; 02404 int x, len = 0; 02405 char *disconnect_code = NULL, *dialed_code = NULL; 02406 02407 if (!(chan = ast_request(type, format, caller, data, &cause))) { 02408 ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data); 02409 switch(cause) { 02410 case AST_CAUSE_BUSY: 02411 state = AST_CONTROL_BUSY; 02412 break; 02413 case AST_CAUSE_CONGESTION: 02414 state = AST_CONTROL_CONGESTION; 02415 break; 02416 } 02417 goto done; 02418 } 02419 02420 ast_set_callerid(chan, cid_num, cid_name, cid_num); 02421 ast_string_field_set(chan, language, language); 02422 ast_channel_inherit_variables(caller, chan); 02423 pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name); 02424 02425 ast_channel_lock(chan); 02426 ast_connected_line_copy_from_caller(&chan->connected, &caller->cid); 02427 ast_channel_unlock(chan); 02428 02429 if (ast_call(chan, data, timeout)) { 02430 ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data); 02431 goto done; 02432 } 02433 02434 ast_indicate(caller, AST_CONTROL_RINGING); 02435 /* support dialing of the featuremap disconnect code while performing an attended tranfer */ 02436 ast_rwlock_rdlock(&features_lock); 02437 for (x = 0; x < FEATURES_COUNT; x++) { 02438 if (strcasecmp(builtin_features[x].sname, "disconnect")) 02439 continue; 02440 02441 disconnect_code = builtin_features[x].exten; 02442 len = strlen(disconnect_code) + 1; 02443 dialed_code = alloca(len); 02444 memset(dialed_code, 0, len); 02445 break; 02446 } 02447 ast_rwlock_unlock(&features_lock); 02448 x = 0; 02449 started = ast_tvnow(); 02450 to = timeout; 02451 02452 ast_poll_channel_add(caller, chan); 02453 02454 while (!((transferee && ast_check_hangup(transferee)) && (!igncallerstate && ast_check_hangup(caller))) && timeout && (chan->_state != AST_STATE_UP)) { 02455 struct ast_frame *f = NULL; 02456 02457 monitor_chans[0] = caller; 02458 monitor_chans[1] = chan; 02459 active_channel = ast_waitfor_n(monitor_chans, 2, &to); 02460 02461 /* see if the timeout has been violated */ 02462 if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) { 02463 state = AST_CONTROL_UNHOLD; 02464 ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n"); 02465 break; /*doh! timeout*/ 02466 } 02467 02468 if (!active_channel) 02469 continue; 02470 02471 if (chan && (chan == active_channel)){ 02472 if (!ast_strlen_zero(chan->call_forward)) { 02473 if (!(chan = ast_call_forward(caller, chan, &to, format, NULL, outstate))) { 02474 return NULL; 02475 } 02476 continue; 02477 } 02478 f = ast_read(chan); 02479 if (f == NULL) { /*doh! where'd he go?*/ 02480 state = AST_CONTROL_HANGUP; 02481 res = 0; 02482 break; 02483 } 02484 02485 if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) { 02486 if (f->subclass == AST_CONTROL_RINGING) { 02487 state = f->subclass; 02488 ast_verb(3, "%s is ringing\n", chan->name); 02489 ast_indicate(caller, AST_CONTROL_RINGING); 02490 } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) { 02491 state = f->subclass; 02492 ast_verb(3, "%s is busy\n", chan->name); 02493 ast_indicate(caller, AST_CONTROL_BUSY); 02494 ast_frfree(f); 02495 f = NULL; 02496 break; 02497 } else if (f->subclass == AST_CONTROL_ANSWER) { 02498 /* This is what we are hoping for */ 02499 state = f->subclass; 02500 ast_frfree(f); 02501 f = NULL; 02502 ready=1; 02503 break; 02504 } else if (f->subclass == AST_CONTROL_CONNECTED_LINE) { 02505 if (ast_channel_connected_line_macro(chan, caller, f, 1, 1)) { 02506 ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen); 02507 } 02508 } else if (f->subclass != -1 && f->subclass != AST_CONTROL_PROGRESS) { 02509 ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass); 02510 } 02511 /* else who cares */ 02512 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { 02513 ast_write(caller, f); 02514 } 02515 02516 } else if (caller && (active_channel == caller)) { 02517 f = ast_read(caller); 02518 if (f == NULL) { /*doh! where'd he go?*/ 02519 if (!igncallerstate) { 02520 if (ast_check_hangup(caller) && !ast_check_hangup(chan)) { 02521 /* make this a blind transfer */ 02522 ready = 1; 02523 break; 02524 } 02525 state = AST_CONTROL_HANGUP; 02526 res = 0; 02527 break; 02528 } 02529 } else { 02530 02531 if (f->frametype == AST_FRAME_DTMF) { 02532 dialed_code[x++] = f->subclass; 02533 dialed_code[x] = '\0'; 02534 if (strlen(dialed_code) == len) { 02535 x = 0; 02536 } else if (x && strncmp(dialed_code, disconnect_code, x)) { 02537 x = 0; 02538 dialed_code[x] = '\0'; 02539 } 02540 if (*dialed_code && !strcmp(dialed_code, disconnect_code)) { 02541 /* Caller Canceled the call */ 02542 state = AST_CONTROL_UNHOLD; 02543 ast_frfree(f); 02544 f = NULL; 02545 break; 02546 } 02547 } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { 02548 ast_write(chan, f); 02549 } 02550 } 02551 } 02552 if (f) 02553 ast_frfree(f); 02554 } /* end while */ 02555 02556 ast_poll_channel_del(caller, chan); 02557 02558 done: 02559 ast_indicate(caller, -1); 02560 if (chan && ready) { 02561 if (chan->_state == AST_STATE_UP) 02562 state = AST_CONTROL_ANSWER; 02563 res = 0; 02564 } else if (chan) { 02565 res = -1; 02566 ast_hangup(chan); 02567 chan = NULL; 02568 } else { 02569 res = -1; 02570 } 02571 02572 if (outstate) 02573 *outstate = state; 02574 02575 return chan; 02576 }
| static int find_channel_by_group | ( | void * | obj, | |
| void * | arg, | |||
| void * | data, | |||
| int | flags | |||
| ) | [static] |
Definition at line 4709 of file features.c.
References ast_channel::_state, AST_STATE_RING, AST_STATE_RINGING, ast_channel::callgroup, CMP_MATCH, CMP_STOP, ast_channel::pbx, and ast_channel::pickupgroup.
Referenced by ast_pickup_call().
04710 { 04711 struct ast_channel *c = data; 04712 struct ast_channel *chan = obj; 04713 04714 int i = !chan->pbx && 04715 /* Accessing 'chan' here is safe without locking, because there is no way for 04716 the channel do disappear from under us at this point. pickupgroup *could* 04717 change while we're here, but that isn't a problem. */ 04718 (c != chan) && 04719 (chan->pickupgroup & c->callgroup) && 04720 ((chan->_state == AST_STATE_RINGING) || (chan->_state == AST_STATE_RING)); 04721 04722 return i ? CMP_MATCH | CMP_STOP : 0; 04723 }
| static struct ast_call_feature* find_dynamic_feature | ( | const char * | name | ) | [static, read] |
find a call feature by name
Definition at line 2023 of file features.c.
References AST_RWLIST_TRAVERSE, ast_call_feature::feature_entry, and ast_call_feature::sname.
Referenced by feature_interpret_helper(), load_config(), and set_config_flags().
02024 { 02025 struct ast_call_feature *tmp; 02026 02027 AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) { 02028 if (!strcasecmp(tmp->sname, name)) { 02029 break; 02030 } 02031 } 02032 02033 return tmp; 02034 }
| static struct feature_group* find_group | ( | const char * | name | ) | [static, read] |
Find a group by name.
| name | feature name |
| feature | group on success. | |
| NULL | on failure. |
Definition at line 2061 of file features.c.
References AST_LIST_TRAVERSE, and feature_group::gname.
Referenced by feature_interpret_helper().
02061 { 02062 struct feature_group *fg = NULL; 02063 02064 AST_LIST_TRAVERSE(&feature_groups, fg, entry) { 02065 if (!strcasecmp(fg->gname, name)) 02066 break; 02067 } 02068 02069 return fg; 02070 }
| struct ast_parkinglot * find_parkinglot | ( | const char * | name | ) | [read] |
Find parkinglot by name.
Definition at line 3491 of file features.c.
References ao2_find, ast_copy_string(), ast_log(), ast_strlen_zero(), LOG_DEBUG, ast_parkinglot::name, OBJ_POINTER, option_debug, and parkinglots.
Referenced by build_parkinglot(), park_exec_full(), and park_space_reserve().
03492 { 03493 struct ast_parkinglot *parkinglot = NULL; 03494 struct ast_parkinglot tmp_parkinglot; 03495 03496 if (ast_strlen_zero(name)) 03497 return NULL; 03498 03499 ast_copy_string(tmp_parkinglot.name, name, sizeof(tmp_parkinglot.name)); 03500 03501 parkinglot = ao2_find(parkinglots, &tmp_parkinglot, OBJ_POINTER); 03502 03503 if (parkinglot && option_debug) 03504 ast_log(LOG_DEBUG, "Found Parkinglot: %s\n", parkinglot->name); 03505 03506 return parkinglot; 03507 }
| static const char* findparkinglotname | ( | struct ast_channel * | chan | ) | [static] |
Find parking lot name from channel.
Definition at line 609 of file features.c.
References ast_strlen_zero(), ast_channel::parkinglot, and pbx_builtin_getvar_helper().
Referenced by park_exec_full(), and park_space_reserve().
00610 { 00611 const char *temp, *parkinglot = NULL; 00612 00613 /* Check if the channel has a parking lot */ 00614 if (!ast_strlen_zero(chan->parkinglot)) 00615 parkinglot = chan->parkinglot; 00616 00617 /* Channel variables override everything */ 00618 00619 if ((temp = pbx_builtin_getvar_helper(chan, "PARKINGLOT"))) 00620 return temp; 00621 00622 return parkinglot; 00623 }
| static int finishup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 1334 of file features.c.
References ast_autoservice_stop(), AST_CONTROL_UNHOLD, and ast_indicate().
Referenced by builtin_atxfer(), and builtin_blindtransfer().
01335 { 01336 ast_indicate(chan, AST_CONTROL_UNHOLD); 01337 01338 return ast_autoservice_stop(chan); 01339 }
| static char* handle_feature_show | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
CLI command to list configured features.
| e | ||
| cmd | ||
| a |
| CLI_SUCCESS | on success. | |
| NULL | when tab completion is used. |
Definition at line 4283 of file features.c.
References ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli(), ast_pickup_ext(), AST_RWLIST_EMPTY, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_rwlock_rdlock(), ast_rwlock_unlock(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_call_feature::default_exten, ast_call_feature::exten, ast_cli_args::fd, FEATURES_COUNT, features_lock, ast_call_feature::fname, HFS_FORMAT, ast_parkinglot::name, ast_parkinglot::parking_con, parking_ext, ast_parkinglot::parking_start, ast_parkinglot::parking_stop, parkinglots, ast_call_feature::sname, and ast_cli_entry::usage.
04284 { 04285 int i; 04286 struct ast_call_feature *feature; 04287 struct ao2_iterator iter; 04288 struct ast_parkinglot *curlot; 04289 #define HFS_FORMAT "%-25s %-7s %-7s\n" 04290 04291 switch (cmd) { 04292 04293 case CLI_INIT: 04294 e->command = "features show"; 04295 e->usage = 04296 "Usage: features show\n" 04297 " Lists configured features\n"; 04298 return NULL; 04299 case CLI_GENERATE: 04300 return NULL; 04301 } 04302 04303 ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current"); 04304 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------"); 04305 04306 ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */ 04307 04308 ast_rwlock_rdlock(&features_lock); 04309 for (i = 0; i < FEATURES_COUNT; i++) 04310 ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten); 04311 ast_rwlock_unlock(&features_lock); 04312 04313 ast_cli(a->fd, "\n"); 04314 ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current"); 04315 ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------"); 04316 if (AST_RWLIST_EMPTY(&feature_list)) { 04317 ast_cli(a->fd, "(none)\n"); 04318 } else { 04319 AST_RWLIST_RDLOCK(&feature_list); 04320 AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) { 04321 ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten); 04322 } 04323 AST_RWLIST_UNLOCK(&feature_list); 04324 } 04325 04326 // loop through all the parking lots 04327 iter = ao2_iterator_init(parkinglots, 0); 04328 04329 while ((curlot = ao2_iterator_next(&iter))) { 04330 ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name); 04331 ast_cli(a->fd, "------------\n"); 04332 ast_cli(a->fd,"%-22s: %s\n", "Parking extension", parking_ext); 04333 ast_cli(a->fd,"%-22s: %s\n", "Parking context", curlot->parking_con); 04334 ast_cli(a->fd,"%-22s: %d-%d\n", "Parked call extensions", curlot->parking_start, curlot->parking_stop); 04335 ast_cli(a->fd,"\n"); 04336 ao2_ref(curlot, -1); 04337 } 04338 04339 04340 return CLI_SUCCESS; 04341 }
| static char* handle_features_reload | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 4357 of file features.c.
References ast_features_reload(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, and ast_cli_entry::usage.
04358 { 04359 switch (cmd) { 04360 case CLI_INIT: 04361 e->command = "features reload"; 04362 e->usage = 04363 "Usage: features reload\n" 04364 " Reloads configured call features from features.conf\n"; 04365 return NULL; 04366 case CLI_GENERATE: 04367 return NULL; 04368 } 04369 ast_features_reload(); 04370 04371 return CLI_SUCCESS; 04372 }
| static char* handle_parkedcalls | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
CLI command to list parked calls.
| e | ||
| cmd | ||
| a | Check right usage, lock parking lot, display parked calls, unlock parking lot list. |
| CLI_SUCCESS | on success. | |
| CLI_SHOWUSAGE | on incorrect number of arguments. | |
| NULL | when tab completion is used. |
Definition at line 4531 of file features.c.
References ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli_args::argc, ast_cli_entry::args, ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, parkeduser::chan, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, parkeduser::context, ESS, parkeduser::exten, ast_cli_args::fd, ast_channel::name, ast_parkinglot::name, parkeduser::parkingexten, parkinglots, ast_parkinglot::parkings, parkeduser::parkingtime, parkeduser::priority, parkeduser::start, and ast_cli_entry::usage.
04532 { 04533 struct parkeduser *cur; 04534 int numparked = 0; 04535 struct ao2_iterator iter; 04536 struct ast_parkinglot *curlot; 04537 04538 switch (cmd) { 04539 case CLI_INIT: 04540 e->command = "parkedcalls show"; 04541 e->usage = 04542 "Usage: parkedcalls show\n" 04543 " List currently parked calls\n"; 04544 return NULL; 04545 case CLI_GENERATE: 04546 return NULL; 04547 } 04548 04549 if (a->argc > e->args) 04550 return CLI_SHOWUSAGE; 04551 04552 ast_cli(a->fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel" 04553 , "Context", "Extension", "Pri", "Timeout"); 04554 04555 iter = ao2_iterator_init(parkinglots, 0); 04556 while ((curlot = ao2_iterator_next(&iter))) { 04557 int lotparked = 0; 04558 ast_cli(a->fd, "*** Parking lot: %s\n", curlot->name); 04559 04560 AST_LIST_LOCK(&curlot->parkings); 04561 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) { 04562 ast_cli(a->fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n" 04563 ,cur->parkingexten, cur->chan->name, cur->context, cur->exten 04564 ,cur->priority, 04565 (long)(cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)) ); 04566 numparked++; 04567 numparked += lotparked; 04568 } 04569 AST_LIST_UNLOCK(&curlot->parkings); 04570 if (lotparked) 04571 ast_cli(a->fd, " %d parked call%s in parking lot %s\n", lotparked, ESS(lotparked), curlot->name); 04572 04573 ao2_ref(curlot, -1); 04574 } 04575 04576 ast_cli(a->fd, "---\n%d parked call%s in total.\n", numparked, ESS(numparked)); 04577 04578 return CLI_SUCCESS; 04579 }
| static int load_config | ( | void | ) | [static] |
Definition at line 3936 of file features.c.
References adsipark, ao2_lock(), ao2_unlock(), ast_call_feature::app, app, ast_call_feature::app_args, ARRAY_LEN, ast_add_extension2(), ast_calloc, ast_category_browse(), ast_config_destroy(), ast_config_load2(), ast_context_find(), ast_context_find_or_create(), ast_context_remove_extension2(), ast_copy_string(), ast_debug, AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, AST_FEATURE_FLAG_BYBOTH, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_FLAG_NEEDSDTMF, AST_FEATURE_FLAG_ONPEER, AST_FEATURE_FLAG_ONSELF, ast_find_call_feature(), ast_log(), ast_parking_ext(), ast_register_feature(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_set_flag, ast_strdupa, ast_strlen_zero(), ast_true(), ast_unregister_features(), ast_unregister_groups(), ast_variable_browse(), ast_verb, atxfercallbackretries, atxferdropcall, atxferloopdelay, atxfernoanswertimeout, build_parkinglot(), comebacktoorigin, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, courtesytone, DEFAULT_ATXFER_CALLBACK_RETRIES, DEFAULT_ATXFER_DROP_CALL, DEFAULT_ATXFER_LOOP_DELAY, DEFAULT_FEATURE_DIGIT_TIMEOUT, DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER, DEFAULT_PARK_TIME, DEFAULT_PARKINGLOT, default_parkinglot, DEFAULT_TRANSFER_DIGIT_TIMEOUT, ast_call_feature::exten, FEATURE_APP_ARGS_LEN, FEATURE_APP_LEN, feature_exec_app(), FEATURE_EXTEN_LEN, FEATURE_MOH_LEN, FEATURE_SNAME_LEN, featuredigittimeout, find_dynamic_feature(), ast_variable::lineno, LOG_DEBUG, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_call_feature::moh_class, ast_variable::name, ast_variable::next, notify_metermaids(), ast_call_feature::operation, option_debug, park_add_hints(), parkcall, parkedplay, parking_ext, pickup_ext, pickupfailsound, pickupsound, register_group(), register_group_feature(), registrar, remap_feature(), ast_call_feature::sname, strsep(), transferdigittimeout, unmap_features(), ast_variable::value, var, xferfailsound, and xfersound.
03937 { 03938 int start = 0, end = 0; 03939 int res; 03940 int i; 03941 struct ast_context *con = NULL; 03942 struct ast_config *cfg = NULL; 03943 struct ast_variable *var = NULL; 03944 struct feature_group *fg = NULL; 03945 struct ast_flags config_flags = { 0 }; 03946 char old_parking_ext[AST_MAX_EXTENSION]; 03947 char old_parking_con[AST_MAX_EXTENSION] = ""; 03948 char *ctg; 03949 static const char * const categories[] = { 03950 /* Categories in features.conf that are not 03951 * to be parsed as group categories 03952 */ 03953 "general", 03954 "featuremap", 03955 "applicationmap" 03956 }; 03957 03958 if (default_parkinglot) { 03959 strcpy(old_parking_con, default_parkinglot->parking_con); 03960 strcpy(old_parking_ext, parking_ext); 03961 } else { 03962 default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL); 03963 if (default_parkinglot) { 03964 ao2_lock(default_parkinglot); 03965 default_parkinglot->parking_start = 701; 03966 default_parkinglot->parking_stop = 750; 03967 default_parkinglot->parking_offset = 0; 03968 default_parkinglot->parkfindnext = 0; 03969 default_parkinglot->parkingtime = DEFAULT_PARK_TIME; 03970 ao2_unlock(default_parkinglot); 03971 } 03972 } 03973 if (default_parkinglot) { 03974 if (option_debug) 03975 ast_log(LOG_DEBUG, "Configuration of default parkinglot done.\n"); 03976 } else { 03977 ast_log(LOG_ERROR, "Configuration of default parkinglot failed.\n"); 03978 return -1; 03979 } 03980 03981 03982 /* Reset to defaults */ 03983 strcpy(parking_ext, "700"); 03984 strcpy(pickup_ext, "*8"); 03985 courtesytone[0] = '\0'; 03986 strcpy(xfersound, "beep"); 03987 strcpy(xferfailsound, "pbx-invalid"); 03988 pickupsound[0] = '\0'; 03989 pickupfailsound[0] = '\0'; 03990 adsipark = 0; 03991 comebacktoorigin = 1; 03992 03993 default_parkinglot->parkaddhints = 0; 03994 default_parkinglot->parkedcalltransfers = 0; 03995 default_parkinglot->parkedcallreparking = 0; 03996 default_parkinglot->parkedcallrecording = 0; 03997 default_parkinglot->parkedcallhangup = 0; 03998 03999 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 04000 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 04001 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 04002 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY; 04003 atxferdropcall = DEFAULT_ATXFER_DROP_CALL; 04004 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES; 04005 04006 cfg = ast_config_load2("features.conf", "features", config_flags); 04007 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) { 04008 ast_log(LOG_WARNING,"Could not load features.conf\n"); 04009 return 0; 04010 } 04011 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) { 04012 if (!strcasecmp(var->name, "parkext")) { 04013 ast_copy_string(parking_ext, var->value, sizeof(parking_ext)); 04014 } else if (!strcasecmp(var->name, "context")) { 04015 ast_copy_string(default_parkinglot->parking_con, var->value, sizeof(default_parkinglot->parking_con)); 04016 } else if (!strcasecmp(var->name, "parkingtime")) { 04017 if ((sscanf(var->value, "%30d", &default_parkinglot->parkingtime) != 1) || (default_parkinglot->parkingtime < 1)) { 04018 ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value); 04019 default_parkinglot->parkingtime = DEFAULT_PARK_TIME; 04020 } else 04021 default_parkinglot->parkingtime = default_parkinglot->parkingtime * 1000; 04022 } else if (!strcasecmp(var->name, "parkpos")) { 04023 if (sscanf(var->value, "%30d-%30d", &start, &end) != 2) { 04024 ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers at line %d of features.conf\n", var->lineno); 04025 } else if (default_parkinglot) { 04026 default_parkinglot->parking_start = start; 04027 default_parkinglot->parking_stop = end; 04028 } else { 04029 ast_log(LOG_WARNING, "No default parking lot!\n"); 04030 } 04031 } else if (!strcasecmp(var->name, "findslot")) { 04032 default_parkinglot->parkfindnext = (!strcasecmp(var->value, "next")); 04033 } else if (!strcasecmp(var->name, "parkinghints")) { 04034 default_parkinglot->parkaddhints = ast_true(var->value); 04035 } else if (!strcasecmp(var->name, "parkedcalltransfers")) { 04036 if (!strcasecmp(var->value, "both")) 04037 default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH; 04038 else if (!strcasecmp(var->value, "caller")) 04039 default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER; 04040 else if (!strcasecmp(var->value, "callee")) 04041 default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE; 04042 } else if (!strcasecmp(var->name, "parkedcallreparking")) { 04043 if (!strcasecmp(var->value, "both")) 04044 default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYBOTH; 04045 else if (!strcasecmp(var->value, "caller")) 04046 default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLER; 04047 else if (!strcasecmp(var->value, "callee")) 04048 default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLEE; 04049 } else if (!strcasecmp(var->name, "parkedcallhangup")) { 04050 if (!strcasecmp(var->value, "both")) 04051 default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYBOTH; 04052 else if (!strcasecmp(var->value, "caller")) 04053 default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLER; 04054 else if (!strcasecmp(var->value, "callee")) 04055 default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE; 04056 } else if (!strcasecmp(var->name, "parkedcallrecording")) { 04057 if (!strcasecmp(var->value, "both")) 04058 default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYBOTH; 04059 else if (!strcasecmp(var->value, "caller")) 04060 default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLER; 04061 else if (!strcasecmp(var->value, "callee")) 04062 default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE; 04063 } else if (!strcasecmp(var->name, "adsipark")) { 04064 adsipark = ast_true(var->value); 04065 } else if (!strcasecmp(var->name, "transferdigittimeout")) { 04066 if ((sscanf(var->value, "%30d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) { 04067 ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value); 04068 transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; 04069 } else 04070 transferdigittimeout = transferdigittimeout * 1000; 04071 } else if (!strcasecmp(var->name, "featuredigittimeout")) { 04072 if ((sscanf(var->value, "%30d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) { 04073 ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value); 04074 featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; 04075 } 04076 } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) { 04077 if ((sscanf(var->value, "%30d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) { 04078 ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value); 04079 atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER; 04080 } else 04081 atxfernoanswertimeout = atxfernoanswertimeout * 1000; 04082 } else if (!strcasecmp(var->name, "atxferloopdelay")) { 04083 if ((sscanf(var->value, "%30u", &atxferloopdelay) != 1)) { 04084 ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value); 04085 atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY; 04086 } else 04087 atxferloopdelay *= 1000; 04088 } else if (!strcasecmp(var->name, "atxferdropcall")) { 04089 atxferdropcall = ast_true(var->value); 04090 } else if (!strcasecmp(var->name, "atxfercallbackretries")) { 04091 if ((sscanf(var->value, "%30u", &atxferloopdelay) != 1)) { 04092 ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value); 04093 atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES; 04094 } 04095 } else if (!strcasecmp(var->name, "courtesytone")) { 04096 ast_copy_string(courtesytone, var->value, sizeof(courtesytone)); 04097 } else if (!strcasecmp(var->name, "parkedplay")) { 04098 if (!strcasecmp(var->value, "both")) 04099 parkedplay = 2; 04100 else if (!strcasecmp(var->value, "parked")) 04101 parkedplay = 1; 04102 else 04103 parkedplay = 0; 04104 } else if (!strcasecmp(var->name, "xfersound")) { 04105 ast_copy_string(xfersound, var->value, sizeof(xfersound)); 04106 } else if (!strcasecmp(var->name, "xferfailsound")) { 04107 ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound)); 04108 } else if (!strcasecmp(var->name, "pickupexten")) { 04109 ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext)); 04110 } else if (!strcasecmp(var->name, "pickupsound")) { 04111 ast_copy_string(pickupsound, var->value, sizeof(pickupsound)); 04112 } else if (!strcasecmp(var->name, "pickupfailsound")) { 04113 ast_copy_string(pickupfailsound, var->value, sizeof(pickupfailsound)); 04114 } else if (!strcasecmp(var->name, "comebacktoorigin")) { 04115 comebacktoorigin = ast_true(var->value); 04116 } else if (!strcasecmp(var->name, "parkedmusicclass")) { 04117 ast_copy_string(default_parkinglot->mohclass, var->value, sizeof(default_parkinglot->mohclass)); 04118 } 04119 } 04120 04121 unmap_features(); 04122 for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) { 04123 if (remap_feature(var->name, var->value)) 04124 ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); 04125 } 04126 04127 /* Map a key combination to an application*/ 04128 ast_unregister_features(); 04129 for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) { 04130 char *tmp_val = ast_strdupa(var->value); 04131 char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 04132 struct ast_call_feature *feature; 04133 04134 /* strsep() sets the argument to NULL if match not found, and it 04135 * is safe to use it with a NULL argument, so we don't check 04136 * between calls. 04137 */ 04138 exten = strsep(&tmp_val,","); 04139 activatedby = strsep(&tmp_val,","); 04140 app = strsep(&tmp_val,","); 04141 app_args = strsep(&tmp_val,","); 04142 moh_class = strsep(&tmp_val,","); 04143 04144 activateon = strsep(&activatedby, "/"); 04145 04146 /*! \todo XXX var_name or app_args ? */ 04147 if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) { 04148 ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n", 04149 app, exten, activateon, var->name); 04150 continue; 04151 } 04152 04153 AST_RWLIST_RDLOCK(&feature_list); 04154 if ((feature = find_dynamic_feature(var->name))) { 04155 AST_RWLIST_UNLOCK(&feature_list); 04156 ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name); 04157 continue; 04158 } 04159 AST_RWLIST_UNLOCK(&feature_list); 04160 04161 if (!(feature = ast_calloc(1, sizeof(*feature)))) 04162 continue; 04163 04164 ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN); 04165 ast_copy_string(feature->app, app, FEATURE_APP_LEN); 04166 ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN); 04167 04168 if (app_args) 04169 ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN); 04170 04171 if (moh_class) 04172 ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN); 04173 04174 ast_copy_string(feature->exten, exten, sizeof(feature->exten)); 04175 feature->operation = feature_exec_app; 04176 ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF); 04177 04178 /* Allow caller and calle to be specified for backwards compatability */ 04179 if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller")) 04180 ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF); 04181 else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee")) 04182 ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER); 04183 else { 04184 ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s'," 04185 " must be 'self', or 'peer'\n", var->name); 04186 continue; 04187 } 04188 04189 if (ast_strlen_zero(activatedby)) 04190 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 04191 else if (!strcasecmp(activatedby, "caller")) 04192 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER); 04193 else if (!strcasecmp(activatedby, "callee")) 04194 ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE); 04195 else if (!strcasecmp(activatedby, "both")) 04196 ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH); 04197 else { 04198 ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s'," 04199 " must be 'caller', or 'callee', or 'both'\n", var->name); 04200 continue; 04201 } 04202 04203 ast_register_feature(feature); 04204 04205 ast_verb(2, "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten); 04206 } 04207 04208 ast_unregister_groups(); 04209 AST_RWLIST_WRLOCK(&feature_groups); 04210 04211 ctg = NULL; 04212 while ((ctg = ast_category_browse(cfg, ctg))) { 04213 /* Is this a parkinglot definition ? */ 04214 if (!strncasecmp(ctg, "parkinglot_", strlen("parkinglot_"))) { 04215 ast_debug(2, "Found configuration section %s, assume parking context\n", ctg); 04216 if(!build_parkinglot(ctg, ast_variable_browse(cfg, ctg))) 04217 ast_log(LOG_ERROR, "Could not build parking lot %s. Configuration error.\n", ctg); 04218 else 04219 ast_debug(1, "Configured parking context %s\n", ctg); 04220 continue; 04221 } 04222 /* No, check if it's a group */ 04223 for (i = 0; i < ARRAY_LEN(categories); i++) { 04224 if (!strcasecmp(categories[i], ctg)) 04225 break; 04226 } 04227 04228 if (i < ARRAY_LEN(categories)) 04229 continue; 04230 04231 if (!(fg = register_group(ctg))) 04232 continue; 04233 04234 for (var = ast_variable_browse(cfg, ctg); var; var = var->next) { 04235 struct ast_call_feature *feature; 04236 04237 AST_RWLIST_RDLOCK(&feature_list); 04238 if (!(feature = find_dynamic_feature(var->name)) && 04239 !(feature = ast_find_call_feature(var->name))) { 04240 AST_RWLIST_UNLOCK(&feature_list); 04241 ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name); 04242 continue; 04243 } 04244 AST_RWLIST_UNLOCK(&feature_list); 04245 04246 register_group_feature(fg, var->value, feature); 04247 } 04248 } 04249 04250 AST_RWLIST_UNLOCK(&feature_groups); 04251 04252 ast_config_destroy(cfg); 04253 04254 /* Remove the old parking extension */ 04255 if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) { 04256 if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar, 0)) 04257 notify_metermaids(old_parking_ext, old_parking_con, AST_DEVICE_NOT_INUSE); 04258 ast_debug(1, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con); 04259 } 04260 04261 if (!(con = ast_context_find_or_create(NULL, NULL, default_parkinglot->parking_con, registrar))) { 04262 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", default_parkinglot->parking_con); 04263 return -1; 04264 } 04265 res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar); 04266 if (default_parkinglot->parkaddhints) 04267 park_add_hints(default_parkinglot->parking_con, default_parkinglot->parking_start, default_parkinglot->parking_stop); 04268 if (!res) 04269 notify_metermaids(ast_parking_ext(), default_parkinglot->parking_con, AST_DEVICE_INUSE); 04270 return res; 04271 04272 }
| int manage_parkinglot | ( | struct ast_parkinglot * | curlot, | |
| fd_set * | rfds, | |||
| fd_set * | efds, | |||
| fd_set * | nrfds, | |||
| fd_set * | nefds, | |||
| int * | fs, | |||
| int * | max | |||
| ) |
Run management on parkinglots, called once per parkinglot.
Definition at line 3274 of file features.c.
References ast_add_extension2(), AST_CEL_PARK_END, ast_cel_report_event(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_clear_flag, ast_context_find(), ast_context_find_or_create(), ast_context_remove_extension2(), AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, ast_copy_string(), ast_debug, AST_DEVICE_NOT_INUSE, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, ast_free_ptr, ast_frfree, ast_hangup(), ast_indicate(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), AST_MAX_FDS, ast_pbx_start(), ast_read(), ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, buf, callback_dialoptions(), parkeduser::chan, comebacktoorigin, ast_channel::context, parkeduser::context, ast_datastore::data, ast_channel::exten, parkeduser::exten, f, ast_channel::fdno, ast_channel::fds, ast_dial_features::features_callee, ast_dial_features::features_caller, ast_frame::frametype, free, ast_channel::generatordata, LOG_ERROR, LOG_WARNING, MAX_DIAL_FEATURE_OPTIONS, parkeduser::moh_trys, ast_parkinglot::mohclass, ast_parkinglot::name, ast_channel::name, notify_metermaids(), parkeduser::notquiteyet, parkeduser::options_specified, ast_parkinglot::parking_con, ast_parkinglot::parking_con_dial, parkeduser::parkingexten, parkeduser::parkinglot, parkeduser::parkingnum, ast_parkinglot::parkings, parkeduser::parkingtime, pbx_builtin_setvar_helper(), parkeduser::peername, post_manager_event(), ast_channel::priority, parkeduser::priority, registrar, S_OR, set_c_e_p(), parkeduser::start, and ast_frame::subclass.
Referenced by do_parking_thread().
03275 { 03276 03277 struct parkeduser *pu; 03278 int res = 0; 03279 char parkingslot[AST_MAX_EXTENSION]; 03280 03281 /* Lock parking list */ 03282 AST_LIST_LOCK(&curlot->parkings); 03283 AST_LIST_TRAVERSE_SAFE_BEGIN(&curlot->parkings, pu, list) { 03284 struct ast_channel *chan = pu->chan; /* shorthand */ 03285 int tms; /* timeout for this item */ 03286 int x; /* fd index in channel */ 03287 struct ast_context *con; 03288 03289 if (pu->notquiteyet) { /* Pretend this one isn't here yet */ 03290 continue; 03291 } 03292 tms = ast_tvdiff_ms(ast_tvnow(), pu->start); 03293 if (tms > pu->parkingtime) { 03294 /* Stop music on hold */ 03295 ast_indicate(pu->chan, AST_CONTROL_UNHOLD); 03296 /* Get chan, exten from derived kludge */ 03297 if (pu->peername[0]) { 03298 char *peername = ast_strdupa(pu->peername); 03299 char *cp = strrchr(peername, '-'); 03300 char peername_flat[AST_MAX_EXTENSION]; /* using something like DAHDI/52 for an extension name is NOT a good idea */ 03301 int i; 03302 03303 if (cp) 03304 *cp = 0; 03305 ast_copy_string(peername_flat,peername,sizeof(peername_flat)); 03306 for(i=0; peername_flat[i] && i < AST_MAX_EXTENSION; i++) { 03307 if (peername_flat[i] == '/') 03308 peername_flat[i]= '0'; 03309 } 03310 con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con_dial, registrar); 03311 if (!con) { 03312 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con_dial); 03313 } 03314 if (con) { 03315 char returnexten[AST_MAX_EXTENSION]; 03316 struct ast_datastore *features_datastore; 03317 struct ast_dial_features *dialfeatures = NULL; 03318 03319 ast_channel_lock(chan); 03320 03321 if ((features_datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL))) 03322 dialfeatures = features_datastore->data; 03323 03324 ast_channel_unlock(chan); 03325 03326 if (!strncmp(peername, "Parked/", 7)) { 03327 peername += 7; 03328 } 03329 03330 if (dialfeatures) { 03331 char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,}; 03332 snprintf(returnexten, sizeof(returnexten), "%s,30,%s", peername, callback_dialoptions(&(dialfeatures->features_callee), &(dialfeatures->features_caller), buf, sizeof(buf))); 03333 } else { /* Existing default */ 03334 ast_log(LOG_WARNING, "Dialfeatures not found on %s, using default!\n", chan->name); 03335 snprintf(returnexten, sizeof(returnexten), "%s,30,t", peername); 03336 } 03337 03338 ast_add_extension2(con, 1, peername_flat, 1, NULL, NULL, "Dial", ast_strdup(returnexten), ast_free_ptr, registrar); 03339 } 03340 if (pu->options_specified == 1) { 03341 /* Park() was called with overriding return arguments, respect those arguments */ 03342 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 03343 } else { 03344 if (comebacktoorigin) { 03345 set_c_e_p(chan, pu->parkinglot->parking_con_dial, peername_flat, 1); 03346 } else { 03347 ast_log(LOG_WARNING, "now going to parkedcallstimeout,s,1 | ps is %d\n",pu->parkingnum); 03348 snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum); 03349 pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot); 03350 set_c_e_p(chan, "parkedcallstimeout", peername_flat, 1); 03351 } 03352 } 03353 } else { 03354 /* They've been waiting too long, send them back to where they came. Theoretically they 03355 should have their original extensions and such, but we copy to be on the safe side */ 03356 set_c_e_p(chan, pu->context, pu->exten, pu->priority); 03357 } 03358 post_manager_event("ParkedCallTimeOut", pu); 03359 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallTimeOut", NULL); 03360 03361 ast_verb(2, "Timeout for %s parked on %d (%s). Returning to %s,%s,%d\n", pu->chan->name, pu->parkingnum, pu->parkinglot->name, pu->chan->context, pu->chan->exten, pu->chan->priority); 03362 /* Start up the PBX, or hang them up */ 03363 if (ast_pbx_start(chan)) { 03364 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name); 03365 ast_hangup(chan); 03366 } 03367 /* And take them out of the parking lot */ 03368 con = ast_context_find(pu->parkinglot->parking_con); 03369 if (con) { 03370 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) 03371 ast_log(LOG_WARNING, "Whoa, failed to remove the parking extension!\n"); 03372 else 03373 notify_metermaids(pu->parkingexten, curlot->parking_con, AST_DEVICE_NOT_INUSE); 03374 } else 03375 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 03376 AST_LIST_REMOVE_CURRENT(list); 03377 free(pu); 03378 } else { /* still within parking time, process descriptors */ 03379 for (x = 0; x < AST_MAX_FDS; x++) { 03380 struct ast_frame *f; 03381 03382 if ((chan->fds[x] == -1) || (!FD_ISSET(chan->fds[x], rfds) && !FD_ISSET(pu->chan->fds[x], efds))) 03383 continue; 03384 03385 if (FD_ISSET(chan->fds[x], efds)) 03386 ast_set_flag(chan, AST_FLAG_EXCEPTION); 03387 else 03388 ast_clear_flag(chan, AST_FLAG_EXCEPTION); 03389 chan->fdno = x; 03390 03391 /* See if they need servicing */ 03392 f = ast_read(pu->chan); 03393 /* Hangup? */ 03394 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) { 03395 if (f) 03396 ast_frfree(f); 03397 post_manager_event("ParkedCallGiveUp", pu); 03398 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "ParkedCallGiveUp", NULL); 03399 03400 /* There's a problem, hang them up*/ 03401 ast_verb(2, "%s got tired of being parked\n", chan->name); 03402 ast_hangup(chan); 03403 /* And take them out of the parking lot */ 03404 con = ast_context_find(curlot->parking_con); 03405 if (con) { 03406 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) 03407 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 03408 else 03409 notify_metermaids(pu->parkingexten, curlot->parking_con, AST_DEVICE_NOT_INUSE); 03410 } else 03411 ast_log(LOG_WARNING, "Whoa, no parking context for parking lot %s?\n", curlot->name); 03412 AST_LIST_REMOVE_CURRENT(list); 03413 free(pu); 03414 break; 03415 } else { 03416 /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ 03417 ast_frfree(f); 03418 if (pu->moh_trys < 3 && !chan->generatordata) { 03419 ast_debug(1, "MOH on parked call stopped by outside source. Restarting on channel %s.\n", chan->name); 03420 ast_indicate_data(chan, AST_CONTROL_HOLD, 03421 S_OR(curlot->mohclass, NULL), 03422 (!ast_strlen_zero(curlot->mohclass) ? strlen(curlot->mohclass) + 1 : 0)); 03423 pu->moh_trys++; 03424 } 03425 goto std; /* XXX Ick: jumping into an else statement??? XXX */ 03426 } 03427 } /* End for */ 03428 if (x >= AST_MAX_FDS) { 03429 std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */ 03430 if (chan->fds[x] > -1) { 03431 FD_SET(chan->fds[x], nrfds); 03432 FD_SET(chan->fds[x], nefds); 03433 if (chan->fds[x] > *max) 03434 *max = chan->fds[x]; 03435 } 03436 } 03437 /* Keep track of our shortest wait */ 03438 if (tms < *ms || *ms < 0) 03439 *ms = tms; 03440 } 03441 } 03442 } 03443 AST_LIST_TRAVERSE_SAFE_END; 03444 AST_LIST_UNLOCK(&curlot->parkings); 03445 return res; 03446 }
| static int manager_park | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Create manager event for parked calls.
| s | ||
| m | Get channels involved in park, create event. |
Definition at line 4649 of file features.c.
References ast_channel_get_by_name(), ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_channel_unref, ast_masq_park_call(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), buf, and CHANNEL_DEADLOCK_AVOIDANCE.
Referenced by ast_features_init().
04650 { 04651 const char *channel = astman_get_header(m, "Channel"); 04652 const char *channel2 = astman_get_header(m, "Channel2"); 04653 const char *timeout = astman_get_header(m, "Timeout"); 04654 char buf[BUFSIZ]; 04655 int to = 0; 04656 int res = 0; 04657 int parkExt = 0; 04658 struct ast_channel *ch1, *ch2; 04659 04660 if (ast_strlen_zero(channel)) { 04661 astman_send_error(s, m, "Channel not specified"); 04662 return 0; 04663 } 04664 04665 if (ast_strlen_zero(channel2)) { 04666 astman_send_error(s, m, "Channel2 not specified"); 04667 return 0; 04668 } 04669 04670 if (!(ch1 = ast_channel_get_by_name(channel))) { 04671 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel); 04672 astman_send_error(s, m, buf); 04673 return 0; 04674 } 04675 04676 if (!(ch2 = ast_channel_get_by_name(channel2))) { 04677 snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2); 04678 astman_send_error(s, m, buf); 04679 ast_channel_unref(ch1); 04680 return 0; 04681 } 04682 04683 ast_channel_lock(ch1); 04684 while (ast_channel_trylock(ch2)) { 04685 CHANNEL_DEADLOCK_AVOIDANCE(ch1); 04686 } 04687 04688 if (!ast_strlen_zero(timeout)) { 04689 sscanf(timeout, "%30d", &to); 04690 } 04691 04692 res = ast_masq_park_call(ch1, ch2, to, &parkExt); 04693 if (!res) { 04694 ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT); 04695 astman_send_ack(s, m, "Park successful"); 04696 } else { 04697 astman_send_error(s, m, "Park failure"); 04698 } 04699 04700 ast_channel_unlock(ch1); 04701 ast_channel_unlock(ch2); 04702 04703 ch1 = ast_channel_unref(ch1); 04704 ch2 = ast_channel_unref(ch2); 04705 04706 return 0; 04707 }
| static int manager_parking_status | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Dump parking lot status.
| s | ||
| m | Lock parking lot, iterate list and append parked calls status, unlock parking lot. |
Definition at line 4595 of file features.c.
References ao2_iterator_init(), ao2_iterator_next, ao2_ref, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_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, ast_channel::name, parkinglots, parkeduser::parkingnum, ast_parkinglot::parkings, parkeduser::parkingtime, parkeduser::peername, RESULT_SUCCESS, S_OR, and parkeduser::start.
Referenced by ast_features_init().
04596 { 04597 struct parkeduser *cur; 04598 const char *id = astman_get_header(m, "ActionID"); 04599 char idText[256] = ""; 04600 struct ao2_iterator iter; 04601 struct ast_parkinglot *curlot; 04602 04603 if (!ast_strlen_zero(id)) 04604 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id); 04605 04606 astman_send_ack(s, m, "Parked calls will follow"); 04607 04608 iter = ao2_iterator_init(parkinglots, 0); 04609 while ((curlot = ao2_iterator_next(&iter))) { 04610 04611 AST_LIST_LOCK(&curlot->parkings); 04612 AST_LIST_TRAVERSE(&curlot->parkings, cur, list) { 04613 astman_append(s, "Event: ParkedCall\r\n" 04614 "Exten: %d\r\n" 04615 "Channel: %s\r\n" 04616 "From: %s\r\n" 04617 "Timeout: %ld\r\n" 04618 "CallerIDNum: %s\r\n" 04619 "CallerIDName: %s\r\n" 04620 "%s" 04621 "\r\n", 04622 cur->parkingnum, cur->chan->name, cur->peername, 04623 (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL), 04624 S_OR(cur->chan->cid.cid_num, ""), /* XXX in other places it is <unknown> */ 04625 S_OR(cur->chan->cid.cid_name, ""), 04626 idText); 04627 } 04628 AST_LIST_UNLOCK(&curlot->parkings); 04629 ao2_ref(curlot, -1); 04630 } 04631 04632 astman_append(s, 04633 "Event: ParkedCallsComplete\r\n" 04634 "%s" 04635 "\r\n",idText); 04636 04637 04638 return RESULT_SUCCESS; 04639 }
| static int masq_park_call | ( | struct ast_channel * | rchan, | |
| struct ast_channel * | peer, | |||
| int | timeout, | |||
| int * | extout, | |||
| int | play_announcement, | |||
| struct ast_park_call_args * | args | |||
| ) | [static] |
Definition at line 954 of file features.c.
References ast_channel::accountcode, ast_channel::amaflags, ast_channel_alloc, ast_channel_masquerade(), AST_FEATURE_RETURN_PARKFAILED, ast_frfree, ast_hangup(), ast_log(), ast_read(), AST_STATE_DOWN, ast_strdupa, ast_stream_and_wait(), ast_channel::context, ast_channel::exten, ast_park_call_args::extout, f, ast_channel::linkedid, LOG_WARNING, ast_channel::name, ast_park_call_args::orig_chan_name, park_call_full(), park_space_reserve(), ast_channel::priority, ast_park_call_args::pu, ast_channel::readformat, set_c_e_p(), ast_park_call_args::timeout, and ast_channel::writeformat.
Referenced by ast_masq_park_call(), masq_park_call_announce(), and masq_park_call_announce_args().
00955 { 00956 struct ast_channel *chan; 00957 struct ast_frame *f; 00958 int park_status; 00959 struct ast_park_call_args park_args = {0,}; 00960 00961 if (!args) { 00962 args = &park_args; 00963 args->timeout = timeout; 00964 args->extout = extout; 00965 } 00966 00967 if ((args->pu = park_space_reserve(rchan, peer, args)) == NULL) { 00968 if (peer) 00969 ast_stream_and_wait(peer, "beeperr", ""); 00970 return AST_FEATURE_RETURN_PARKFAILED; 00971 } 00972 00973 /* Make a new, fake channel that we'll use to masquerade in the real one */ 00974 if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->linkedid, rchan->amaflags, "Parked/%s",rchan->name))) { 00975 ast_log(LOG_WARNING, "Unable to create parked channel\n"); 00976 return -1; 00977 } 00978 00979 /* Make formats okay */ 00980 chan->readformat = rchan->readformat; 00981 chan->writeformat = rchan->writeformat; 00982 ast_channel_masquerade(chan, rchan); 00983 00984 /* Setup the extensions and such */ 00985 set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority); 00986 00987 /* Make the masq execute */ 00988 if ((f = ast_read(chan))) 00989 ast_frfree(f); 00990 00991 if (peer == rchan) { 00992 peer = chan; 00993 } 00994 00995 if (!play_announcement && args == &park_args) { 00996 args->orig_chan_name = ast_strdupa(chan->name); 00997 } 00998 00999 park_status = park_call_full(chan, peer, args); 01000 if (park_status == 1) { 01001 /* would be nice to play "invalid parking extension" */ 01002 ast_hangup(chan); 01003 return -1; 01004 } 01005 01006 return 0; 01007 }
| static int masq_park_call_announce | ( | struct ast_channel * | rchan, | |
| struct ast_channel * | peer, | |||
| int | timeout, | |||
| int * | extout | |||
| ) | [static] |
Definition at line 1020 of file features.c.
References masq_park_call().
Referenced by builtin_blindtransfer(), and builtin_parkcall().
01021 { 01022 return masq_park_call(rchan, peer, timeout, extout, 1, NULL); 01023 }
| static int masq_park_call_announce_args | ( | struct ast_channel * | rchan, | |
| struct ast_channel * | peer, | |||
| struct ast_park_call_args * | args | |||
| ) | [static] |
Definition at line 1015 of file features.c.
References masq_park_call().
Referenced by park_call_exec().
01016 { 01017 return masq_park_call(rchan, peer, 0, NULL, 1, args); 01018 }
| static enum ast_device_state metermaidstate | ( | const char * | data | ) | [static] |
metermaids callback from devicestate.c
Definition at line 635 of file features.c.
References ast_debug, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, ast_exists_extension(), ast_strdupa, and strsep().
Referenced by ast_features_init().
00636 { 00637 char *context; 00638 char *exten; 00639 00640 context = ast_strdupa(data); 00641 00642 exten = strsep(&context, "@"); 00643 if (!context) 00644 return AST_DEVICE_INVALID; 00645 00646 ast_debug(4, "Checking state of exten %s in context %s\n", exten, context); 00647 00648 if (!ast_exists_extension(NULL, context, exten, 1, NULL)) 00649 return AST_DEVICE_NOT_INUSE; 00650 00651 return AST_DEVICE_INUSE; 00652 }
| static void notify_metermaids | ( | const char * | exten, | |
| char * | context, | |||
| enum ast_device_state | state | |||
| ) | [static] |
Notify metermaids that we've changed an extension.
Definition at line 626 of file features.c.
References ast_debug, ast_devstate2str(), and ast_devstate_changed().
Referenced by load_config(), manage_parkinglot(), park_call_full(), and park_exec_full().
00627 { 00628 ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'", 00629 exten, context, ast_devstate2str(state)); 00630 00631 ast_devstate_changed(state, "park:%s@%s", exten, context); 00632 }
| static void park_add_hints | ( | char * | context, | |
| int | start, | |||
| int | stop | |||
| ) | [static] |
Add parking hints for all defined parking lots.
Definition at line 3923 of file features.c.
References ast_add_extension(), PRIORITY_HINT, and registrar.
Referenced by load_config().
03924 { 03925 int numext; 03926 char device[AST_MAX_EXTENSION]; 03927 char exten[10]; 03928 03929 for (numext = start; numext <= stop; numext++) { 03930 snprintf(exten, sizeof(exten), "%d", numext); 03931 snprintf(device, sizeof(device), "park:%s@%s", exten, context); 03932 ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar); 03933 } 03934 }
| static int park_call_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
Park a call.
Definition at line 3516 of file features.c.
References ast_channel::_state, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_copy_string(), AST_DECLARE_APP_ARGS, ast_log(), ast_safe_sleep(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_channel::exten, ast_flags::flags, ast_park_call_args::flags, LOG_WARNING, masq_park_call_announce_args(), ast_channel::name, ast_park_call_args::orig_chan_name, orig_exten(), park_call_options, parse(), ast_channel::priority, ast_park_call_args::return_con, ast_park_call_args::return_ext, ast_park_call_args::return_pri, and ast_park_call_args::timeout.
Referenced by ast_features_init().
03517 { 03518 /* Cache the original channel name in case we get masqueraded in the middle 03519 * of a park--it is still theoretically possible for a transfer to happen before 03520 * we get here, but it is _really_ unlikely */ 03521 char *orig_chan_name = ast_strdupa(chan->name); 03522 char orig_exten[AST_MAX_EXTENSION]; 03523 int orig_priority = chan->priority; 03524 03525 /* Data is unused at the moment but could contain a parking 03526 lot context eventually */ 03527 int res = 0; 03528 03529 char *parse = NULL; 03530 AST_DECLARE_APP_ARGS(app_args, 03531 AST_APP_ARG(timeout); 03532 AST_APP_ARG(return_con); 03533 AST_APP_ARG(return_ext); 03534 AST_APP_ARG(return_pri); 03535 AST_APP_ARG(options); 03536 ); 03537 03538 parse = ast_strdupa(data); 03539 AST_STANDARD_APP_ARGS(app_args, parse); 03540 03541 ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten)); 03542 03543 /* Setup the exten/priority to be s/1 since we don't know 03544 where this call should return */ 03545 strcpy(chan->exten, "s"); 03546 chan->priority = 1; 03547 03548 /* Answer if call is not up */ 03549 if (chan->_state != AST_STATE_UP) 03550 res = ast_answer(chan); 03551 03552 /* Sleep to allow VoIP streams to settle down */ 03553 if (!res) 03554 res = ast_safe_sleep(chan, 1000); 03555 03556 /* Park the call */ 03557 if (!res) { 03558 struct ast_park_call_args args = { 03559 .orig_chan_name = orig_chan_name, 03560 }; 03561 struct ast_flags flags = { 0 }; 03562 03563 if (parse) { 03564 if (!ast_strlen_zero(app_args.timeout)) { 03565 if (sscanf(app_args.timeout, "%30d", &args.timeout) != 1) { 03566 ast_log(LOG_WARNING, "Invalid timeout '%s' provided\n", app_args.timeout); 03567 args.timeout = 0; 03568 } 03569 } 03570 if (!ast_strlen_zero(app_args.return_con)) { 03571 args.return_con = app_args.return_con; 03572 } 03573 if (!ast_strlen_zero(app_args.return_ext)) { 03574 args.return_ext = app_args.return_ext; 03575 } 03576 if (!ast_strlen_zero(app_args.return_pri)) { 03577 if (sscanf(app_args.return_pri, "%30d", &args.return_pri) != 1) { 03578 ast_log(LOG_WARNING, "Invalid priority '%s' specified\n", app_args.return_pri); 03579 args.return_pri = 0; 03580 } 03581 } 03582 } 03583 03584 ast_app_parse_options(park_call_options, &flags, NULL, app_args.options); 03585 args.flags = flags.flags; 03586 03587 res = masq_park_call_announce_args(chan, chan, &args); 03588 /* Continue on in the dialplan */ 03589 if (res == 1) { 03590 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten)); 03591 chan->priority = orig_priority; 03592 res = 0; 03593 } else if (!res) { 03594 res = 1; 03595 } 03596 } 03597 03598 return res; 03599 }
| static int park_call_full | ( | struct ast_channel * | chan, | |
| struct ast_channel * | peer, | |||
| struct ast_park_call_args * | args | |||
| ) | [static] |
Definition at line 795 of file features.c.
References adsi_announce_park(), adsipark, ast_channel::appl, ast_add_extension2(), ast_adsi_available, ast_adsi_unload_session, ast_bridged_channel(), AST_CEL_PARK_START, ast_cel_report_event(), ast_channel_get_by_name(), ast_channel_lock, AST_CHANNEL_NAME, ast_channel_unlock, ast_channel_unref, ast_clear_flag, ast_context_find_or_create(), AST_CONTROL_HOLD, AST_CONTROL_RINGING, ast_copy_string(), AST_DEVICE_INUSE, AST_FLAG_MASQ_NOSTREAM, ast_free_ptr, ast_indicate(), ast_indicate_data(), AST_LIST_UNLOCK, ast_log(), AST_PARK_OPT_RINGING, AST_PARK_OPT_SILENCE, ast_say_digits(), ast_set_flag, ast_strdup, ast_strlen_zero(), ast_test_flag, ast_tvnow(), ast_verb, parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::context, parkeduser::context, ast_channel::data, EVENT_FLAG_CALL, ast_channel::exten, parkeduser::exten, ast_park_call_args::extout, ast_channel::language, LOG_ERROR, ast_channel::macrocontext, ast_channel::macroexten, ast_channel::macropriority, manager_event, ast_parkinglot::mohclass, ast_parkinglot::name, ast_channel::name, notify_metermaids(), parkeduser::notquiteyet, parkeduser::options_specified, ast_park_call_args::orig_chan_name, park_space_reserve(), parkedcall, ast_parkinglot::parking_con, parking_thread, parkeduser::parkingexten, parkeduser::parkinglot, parkeduser::parkingnum, ast_parkinglot::parkings, ast_parkinglot::parkingtime, parkeduser::parkingtime, pbx_builtin_getvar_helper(), parkeduser::peername, ast_channel::priority, parkeduser::priority, ast_park_call_args::pu, registrar, ast_park_call_args::return_con, ast_park_call_args::return_ext, ast_park_call_args::return_pri, S_OR, parkeduser::start, ast_channel::tech, ast_park_call_args::timeout, ast_channel_tech::type, and ast_channel::uniqueid.
Referenced by ast_park_call(), and masq_park_call().
00796 { 00797 struct ast_context *con; 00798 int parkingnum_copy; 00799 struct parkeduser *pu = args->pu; 00800 const char *event_from; 00801 00802 if (pu == NULL) 00803 pu = park_space_reserve(chan, peer, args); 00804 if (pu == NULL) 00805 return 1; /* Continue execution if possible */ 00806 00807 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", pu->parkingnum); 00808 00809 chan->appl = "Parked Call"; 00810 chan->data = NULL; 00811 00812 pu->chan = chan; 00813 00814 /* Put the parked channel on hold if we have two different channels */ 00815 if (chan != peer) { 00816 if (ast_test_flag(args, AST_PARK_OPT_RINGING)) { 00817 ast_indicate(pu->chan, AST_CONTROL_RINGING); 00818 } else { 00819 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 00820 S_OR(pu->parkinglot->mohclass, NULL), 00821 !ast_strlen_zero(pu->parkinglot->mohclass) ? strlen(pu->parkinglot->mohclass) + 1 : 0); 00822 } 00823 } 00824 00825 pu->start = ast_tvnow(); 00826 pu->parkingtime = (args->timeout > 0) ? args->timeout : pu->parkinglot->parkingtime; 00827 parkingnum_copy = pu->parkingnum; 00828 if (args->extout) 00829 *(args->extout) = pu->parkingnum; 00830 00831 if (peer) { 00832 /* This is so ugly that it hurts, but implementing get_base_channel() on local channels 00833 could have ugly side effects. We could have transferer<->local,1<->local,2<->parking 00834 and we need the callback name to be that of transferer. Since local,1/2 have the same 00835 name we can be tricky and just grab the bridged channel from the other side of the local 00836 */ 00837 if (!strcasecmp(peer->tech->type, "Local")) { 00838 struct ast_channel *tmpchan, *base_peer; 00839 char other_side[AST_CHANNEL_NAME]; 00840 char *c; 00841 ast_copy_string(other_side, S_OR(args->orig_chan_name, peer->name), sizeof(other_side)); 00842 if ((c = strrchr(other_side, ';'))) { 00843 *++c = '1'; 00844 } 00845 if ((tmpchan = ast_channel_get_by_name(other_side))) { 00846 ast_channel_lock(tmpchan); 00847 if ((base_peer = ast_bridged_channel(tmpchan))) { 00848 ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername)); 00849 } 00850 ast_channel_unlock(tmpchan); 00851 tmpchan = ast_channel_unref(tmpchan); 00852 } 00853 } else { 00854 ast_copy_string(pu->peername, S_OR(args->orig_chan_name, peer->name), sizeof(pu->peername)); 00855 } 00856 } 00857 00858 /* Remember what had been dialed, so that if the parking 00859 expires, we try to come back to the same place */ 00860 00861 pu->options_specified = (!ast_strlen_zero(args->return_con) || !ast_strlen_zero(args->return_ext) || args->return_pri); 00862 00863 /* If extension has options specified, they override all other possibilities 00864 such as the returntoorigin flag and transferred context. Information on 00865 extension options is lost here, so we set a flag */ 00866 00867 ast_copy_string(pu->context, 00868 S_OR(args->return_con, S_OR(chan->macrocontext, chan->context)), 00869 sizeof(pu->context)); 00870 ast_copy_string(pu->exten, 00871 S_OR(args->return_ext, S_OR(chan->macroexten, chan->exten)), 00872 sizeof(pu->exten)); 00873 pu->priority = args->return_pri ? args->return_pri : 00874 (chan->macropriority ? chan->macropriority : chan->priority); 00875 00876 /* If parking a channel directly, don't quiet yet get parking running on it. 00877 * All parking lot entries are put into the parking lot with notquiteyet on. */ 00878 if (peer != chan) 00879 pu->notquiteyet = 0; 00880 00881 /* Wake up the (presumably select()ing) thread */ 00882 pthread_kill(parking_thread, SIGURG); 00883 ast_verb(2, "Parked %s on %d (lot %s). Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, pu->parkinglot->name, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000)); 00884 00885 ast_cel_report_event(pu->chan, AST_CEL_PARK_START, NULL, pu->parkinglot->name, peer); 00886 00887 if (peer) { 00888 event_from = peer->name; 00889 } else { 00890 event_from = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"); 00891 } 00892 00893 manager_event(EVENT_FLAG_CALL, "ParkedCall", 00894 "Exten: %s\r\n" 00895 "Channel: %s\r\n" 00896 "Parkinglot: %s\r\n" 00897 "From: %s\r\n" 00898 "Timeout: %ld\r\n" 00899 "CallerIDNum: %s\r\n" 00900 "CallerIDName: %s\r\n" 00901 "Uniqueid: %s\r\n", 00902 pu->parkingexten, pu->chan->name, pu->parkinglot->name, event_from ? event_from : "", 00903 (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL), 00904 S_OR(pu->chan->cid.cid_num, "<unknown>"), 00905 S_OR(pu->chan->cid.cid_name, "<unknown>"), 00906 pu->chan->uniqueid 00907 ); 00908 00909 if (peer && adsipark && ast_adsi_available(peer)) { 00910 adsi_announce_park(peer, pu->parkingexten); /* Only supports parking numbers */ 00911 ast_adsi_unload_session(peer); 00912 } 00913 00914 con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con, registrar); 00915 if (!con) /* Still no context? Bad */ 00916 ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con); 00917 if (con) { 00918 if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, ast_strdup(pu->parkingexten), ast_free_ptr, registrar)) 00919 notify_metermaids(pu->parkingexten, pu->parkinglot->parking_con, AST_DEVICE_INUSE); 00920 } 00921 00922 AST_LIST_UNLOCK(&pu->parkinglot->parkings); 00923 00924 /* Only say number if it's a number and the channel hasn't been masqueraded away */ 00925 if (peer && !ast_test_flag(args, AST_PARK_OPT_SILENCE) && (ast_strlen_zero(args->orig_chan_name) || !strcasecmp(peer->name, args->orig_chan_name))) { 00926 /* If a channel is masqueraded into peer while playing back the parking slot number do not continue playing it back. This is the case if an attended transfer occurs. */ 00927 ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM); 00928 /* Tell the peer channel the number of the parking space */ 00929 ast_say_digits(peer, pu->parkingnum, "", peer->language); 00930 ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM); 00931 } 00932 if (peer == chan) { /* pu->notquiteyet = 1 */ 00933 /* Wake up parking thread if we're really done */ 00934 ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 00935 S_OR(pu->parkinglot->mohclass, NULL), 00936 !ast_strlen_zero(pu->parkinglot->mohclass) ? strlen(pu->parkinglot->mohclass) + 1 : 0); 00937 pu->notquiteyet = 0; 00938 pthread_kill(parking_thread, SIGURG); 00939 } 00940 return 0; 00941 }
| static int park_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
Definition at line 3766 of file features.c.
References default_parkinglot, and park_exec_full().
Referenced by ast_features_init().
03767 { 03768 return park_exec_full(chan, data, default_parkinglot); 03769 }
| static int park_exec_full | ( | struct ast_channel * | chan, | |
| const char * | data, | |||
| struct ast_parkinglot * | parkinglot | |||
| ) | [static] |
Pickup parked call.
Definition at line 3602 of file features.c.
References ast_channel::_state, ast_answer(), ast_bridge_call(), ast_cdr_setdestchan(), AST_CEL_PARK_END, ast_cel_report_event(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_make_compatible(), ast_channel_unlock, ast_context_find(), ast_context_remove_extension2(), AST_CONTROL_UNHOLD, ast_copy_flags, AST_DEVICE_NOT_INUSE, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_FLAG_BYBOTH, AST_FEATURE_FLAG_BYCALLEE, AST_FEATURE_FLAG_BYCALLER, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, AST_FLAGS_ALL, ast_free, ast_hangup(), ast_indicate(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_set_flag, AST_STATE_UP, ast_stream_and_wait(), ast_streamfile(), ast_strlen_zero(), ast_verb, ast_waitstream(), ast_channel::cdr, parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, courtesytone, ast_datastore::data, default_parkinglot, EVENT_FLAG_CALL, ast_dial_features::features_callee, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_dial_features::features_caller, find_parkinglot(), findparkinglotname(), ast_dial_features::is_caller, ast_channel::language, LOG_WARNING, manager_event, ast_channel::name, notify_metermaids(), ast_parkinglot::parkedcallhangup, ast_parkinglot::parkedcallrecording, ast_parkinglot::parkedcallreparking, ast_parkinglot::parkedcalltransfers, parkedplay, ast_parkinglot::parking_con, parkeduser::parkingexten, parkeduser::parkingnum, ast_parkinglot::parkings, ast_channel::pbx, pbx_builtin_setvar_helper(), and S_OR.
Referenced by park_exec().
03603 { 03604 int res = 0; 03605 struct ast_channel *peer=NULL; 03606 struct parkeduser *pu; 03607 struct ast_context *con; 03608 int park = 0; 03609 struct ast_bridge_config config; 03610 03611 if (data) 03612 park = atoi((char *) data); 03613 03614 parkinglot = find_parkinglot(findparkinglotname(chan)); 03615 if (!parkinglot) 03616 parkinglot = default_parkinglot; 03617 03618 AST_LIST_LOCK(&parkinglot->parkings); 03619 AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot->parkings, pu, list) { 03620 if (!data || pu->parkingnum == park) { 03621 if (pu->chan->pbx) { /* do not allow call to be picked up until the PBX thread is finished */ 03622 AST_LIST_UNLOCK(&parkinglot->parkings); 03623 return -1; 03624 } 03625 AST_LIST_REMOVE_CURRENT(list); 03626 break; 03627 } 03628 } 03629 AST_LIST_TRAVERSE_SAFE_END; 03630 AST_LIST_UNLOCK(&parkinglot->parkings); 03631 03632 if (pu) { 03633 peer = pu->chan; 03634 con = ast_context_find(parkinglot->parking_con); 03635 if (con) { 03636 if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) 03637 ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); 03638 else 03639 notify_metermaids(pu->parkingexten, parkinglot->parking_con, AST_DEVICE_NOT_INUSE); 03640 } else 03641 ast_log(LOG_WARNING, "Whoa, no parking context?\n"); 03642 03643 ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "UnParkedCall", chan); 03644 manager_event(EVENT_FLAG_CALL, "UnParkedCall", 03645 "Exten: %s\r\n" 03646 "Channel: %s\r\n" 03647 "From: %s\r\n" 03648 "CallerIDNum: %s\r\n" 03649 "CallerIDName: %s\r\n", 03650 pu->parkingexten, pu->chan->name, chan->name, 03651 S_OR(pu->chan->cid.cid_num, "<unknown>"), 03652 S_OR(pu->chan->cid.cid_name, "<unknown>") 03653 ); 03654 03655 ast_free(pu); 03656 } 03657 /* JK02: it helps to answer the channel if not already up */ 03658 if (chan->_state != AST_STATE_UP) 03659 ast_answer(chan); 03660 03661 //XXX Why do we unlock here ? 03662 // uncomment it for now, till my setup with debug_threads and detect_deadlocks starts to complain 03663 //ASTOBJ_UNLOCK(parkinglot); 03664 03665 if (peer) { 03666 struct ast_datastore *features_datastore; 03667 struct ast_dial_features *dialfeatures = NULL; 03668 03669 /* Play a courtesy to the source(s) configured to prefix the bridge connecting */ 03670 03671 if (!ast_strlen_zero(courtesytone)) { 03672 int error = 0; 03673 ast_indicate(peer, AST_CONTROL_UNHOLD); 03674 if (parkedplay == 0) { 03675 error = ast_stream_and_wait(chan, courtesytone, ""); 03676 } else if (parkedplay == 1) { 03677 error = ast_stream_and_wait(peer, courtesytone, ""); 03678 } else if (parkedplay == 2) { 03679 if (!ast_streamfile(chan, courtesytone, chan->language) && 03680 !ast_streamfile(peer, courtesytone, chan->language)) { 03681 /*! \todo XXX we would like to wait on both! */ 03682 res = ast_waitstream(chan, ""); 03683 if (res >= 0) 03684 res = ast_waitstream(peer, ""); 03685 if (res < 0) 03686 error = 1; 03687 } 03688 } 03689 if (error) { 03690 ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); 03691 ast_hangup(peer); 03692 return -1; 03693 } 03694 } else 03695 ast_indicate(peer, AST_CONTROL_UNHOLD); 03696 03697 res = ast_channel_make_compatible(chan, peer); 03698 if (res < 0) { 03699 ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); 03700 ast_hangup(peer); 03701 return -1; 03702 } 03703 /* This runs sorta backwards, since we give the incoming channel control, as if it 03704 were the person called. */ 03705 ast_verb(3, "Channel %s connected to parked call %d\n", chan->name, park); 03706 03707 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 03708 ast_cdr_setdestchan(chan->cdr, peer->name); 03709 memset(&config, 0, sizeof(struct ast_bridge_config)); 03710 03711 /* Get datastore for peer and apply it's features to the callee side of the bridge config */ 03712 ast_channel_lock(peer); 03713 if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) { 03714 dialfeatures = features_datastore->data; 03715 } 03716 ast_channel_unlock(peer); 03717 03718 if (dialfeatures) { 03719 ast_copy_flags(&(config.features_callee), dialfeatures->is_caller ? &(dialfeatures->features_caller) : &(dialfeatures->features_callee), AST_FLAGS_ALL); 03720 } 03721 03722 if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 03723 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 03724 } 03725 if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) { 03726 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 03727 } 03728 if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 03729 ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL); 03730 } 03731 if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) { 03732 ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL); 03733 } 03734 if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 03735 ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT); 03736 } 03737 if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) { 03738 ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT); 03739 } 03740 if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 03741 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON); 03742 } 03743 if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) { 03744 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON); 03745 } 03746 03747 res = ast_bridge_call(chan, peer, &config); 03748 03749 pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name); 03750 ast_cdr_setdestchan(chan->cdr, peer->name); 03751 03752 /* Simulate the PBX hanging up */ 03753 ast_hangup(peer); 03754 return -1; 03755 } else { 03756 /*! \todo XXX Play a message XXX */ 03757 if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) 03758 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name); 03759 ast_verb(3, "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park); 03760 res = -1; 03761 } 03762 03763 return -1; 03764 }
| static struct parkeduser* park_space_reserve | ( | struct ast_channel * | chan, | |
| struct ast_channel * | peer, | |||
| struct ast_park_call_args * | args | |||
| ) | [static, read] |
Definition at line 682 of file features.c.
References ast_calloc, ast_channel_lock, ast_channel_unlock, ast_exists_extension(), ast_free, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_PARK_OPT_RANDOMIZE, ast_random(), ast_strlen_zero(), ast_test_flag, default_parkinglot, find_parkinglot(), findparkinglotname(), free, LOG_DEBUG, LOG_WARNING, ast_parkinglot::name, parkeduser::notquiteyet, option_debug, ast_parkinglot::parkfindnext, ast_parkinglot::parking_con, ast_parkinglot::parking_offset, ast_parkinglot::parking_start, ast_parkinglot::parking_stop, parkeduser::parkingexten, parkeduser::parkinglot, parkinglot_addref(), parkinglot_unref(), parkeduser::parkingnum, ast_parkinglot::parkings, and pbx_builtin_getvar_helper().
Referenced by masq_park_call(), and park_call_full().
00684 { 00685 struct parkeduser *pu; 00686 int i, parking_space = -1, parking_range; 00687 const char *parkinglotname = NULL; 00688 const char *parkingexten; 00689 struct ast_parkinglot *parkinglot = NULL; 00690 00691 if (peer) 00692 parkinglotname = findparkinglotname(peer); 00693 00694 if (parkinglotname) { 00695 if (option_debug) 00696 ast_log(LOG_DEBUG, "Found chanvar Parkinglot: %s\n", parkinglotname); 00697 parkinglot = find_parkinglot(parkinglotname); 00698 } 00699 if (!parkinglot) 00700 parkinglot = default_parkinglot; 00701 00702 parkinglot_addref(parkinglot); 00703 if (option_debug) 00704 ast_log(LOG_DEBUG, "Parkinglot: %s\n", parkinglot->name); 00705 00706 /* Allocate memory for parking data */ 00707 if (!(pu = ast_calloc(1, sizeof(*pu)))) { 00708 parkinglot_unref(parkinglot); 00709 return NULL; 00710 } 00711 00712 /* Lock parking list */ 00713 AST_LIST_LOCK(&parkinglot->parkings); 00714 /* Check for channel variable PARKINGEXTEN */ 00715 ast_channel_lock(chan); 00716 parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN"); 00717 ast_channel_unlock(chan); 00718 if (!ast_strlen_zero(parkingexten)) { 00719 /*!\note The API forces us to specify a numeric parking slot, even 00720 * though the architecture would tend to support non-numeric extensions 00721 * (as are possible with SIP, for example). Hence, we enforce that 00722 * limitation here. If extout was not numeric, we could permit 00723 * arbitrary non-numeric extensions. 00724 */ 00725 if (sscanf(parkingexten, "%30d", &parking_space) != 1 || parking_space < 0) { 00726 AST_LIST_UNLOCK(&parkinglot->parkings); 00727 parkinglot_unref(parkinglot); 00728 free(pu); 00729 ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten); 00730 return NULL; 00731 } 00732 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space); 00733 00734 if (ast_exists_extension(NULL, parkinglot->parking_con, pu->parkingexten, 1, NULL)) { 00735 AST_LIST_UNLOCK(&parkinglot->parkings); 00736 parkinglot_unref(parkinglot); 00737 ast_free(pu); 00738 ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parkinglot->parking_con); 00739 return NULL; 00740 } 00741 } else { 00742 int start; 00743 struct parkeduser *cur = NULL; 00744 00745 /* Select parking space within range */ 00746 parking_range = parkinglot->parking_stop - parkinglot->parking_start + 1; 00747 00748 if (ast_test_flag(args, AST_PARK_OPT_RANDOMIZE)) { 00749 start = ast_random() % (parkinglot->parking_stop - parkinglot->parking_start + 1); 00750 } else { 00751 start = parkinglot->parking_start; 00752 } 00753 00754 for (i = start; 1; i++) { 00755 if (i == parkinglot->parking_stop + 1) { 00756 i = parkinglot->parking_start - 1; 00757 continue; 00758 } 00759 00760 AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) { 00761 if (cur->parkingnum == i) { 00762 break; 00763 } 00764 } 00765 00766 if (!cur || i == start - 1) { 00767 parking_space = i; 00768 break; 00769 } 00770 } 00771 00772 if (i == start - 1 && cur) { 00773 ast_log(LOG_WARNING, "No more parking spaces\n"); 00774 ast_free(pu); 00775 AST_LIST_UNLOCK(&parkinglot->parkings); 00776 parkinglot_unref(parkinglot); 00777 return NULL; 00778 } 00779 /* Set pointer for next parking */ 00780 if (parkinglot->parkfindnext) 00781 parkinglot->parking_offset = parking_space - parkinglot->parking_start + 1; 00782 snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space); 00783 } 00784 00785 pu->notquiteyet = 1; 00786 pu->parkingnum = parking_space; 00787 pu->parkinglot = parkinglot; 00788 AST_LIST_INSERT_TAIL(&parkinglot->parkings, pu, list); 00789 parkinglot_unref(parkinglot); 00790 00791 return pu; 00792 }
| static struct ast_parkinglot * parkinglot_addref | ( | struct ast_parkinglot * | parkinglot | ) | [static, read] |
Definition at line 3780 of file features.c.
References ao2_ref, ast_log(), LOG_DEBUG, ast_parkinglot::name, and option_debug.
Referenced by park_space_reserve().
03781 { 03782 int refcount = ao2_ref(parkinglot, +1); 03783 if (option_debug > 2) 03784 ast_log(LOG_DEBUG, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount + 1); 03785 return parkinglot; 03786 }
| static int parkinglot_cmp_cb | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 456 of file features.c.
References CMP_MATCH, CMP_STOP, and ast_parkinglot::name.
Referenced by ast_features_init().
00457 { 00458 struct ast_parkinglot *parkinglot = obj, *parkinglot2 = arg; 00459 00460 return !strcasecmp(parkinglot->name, parkinglot2->name) ? CMP_MATCH | CMP_STOP : 0; 00461 }
| static void parkinglot_destroy | ( | void * | obj | ) | [static] |
Destroy a parking lot.
Definition at line 3807 of file features.c.
References ao2_unlink, ast_context_destroy(), ast_context_find(), ast_parkinglot::parking_con, parkinglots, and registrar.
Referenced by build_parkinglot(), and create_parkinglot().
03808 { 03809 struct ast_parkinglot *ruin = obj; 03810 struct ast_context *con; 03811 con = ast_context_find(ruin->parking_con); 03812 if (con) 03813 ast_context_destroy(con, registrar); 03814 ao2_unlink(parkinglots, ruin); 03815 }
| static int parkinglot_hash_cb | ( | const void * | obj, | |
| const int | flags | |||
| ) | [static] |
Definition at line 449 of file features.c.
References ast_str_case_hash(), and ast_parkinglot::name.
Referenced by ast_features_init().
00450 { 00451 const struct ast_parkinglot *parkinglot = obj; 00452 00453 return ast_str_case_hash(parkinglot->name); 00454 }
| static void parkinglot_unref | ( | struct ast_parkinglot * | parkinglot | ) | [static] |
Unreference parkinglot object. If no more references, then go ahead and delete it.
Definition at line 3773 of file features.c.
References ao2_ref, ast_log(), LOG_DEBUG, ast_parkinglot::name, and option_debug.
Referenced by build_parkinglot(), and park_space_reserve().
03774 { 03775 int refcount = ao2_ref(parkinglot, -1); 03776 if (option_debug > 2) 03777 ast_log(LOG_DEBUG, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount - 1); 03778 }
return the first unlocked cdr in a possible chain
Definition at line 2602 of file features.c.
References AST_CDR_FLAG_LOCKED, ast_test_flag, and ast_cdr::next.
Referenced by ast_bridge_call().
02603 { 02604 struct ast_cdr *cdr_orig = cdr; 02605 while (cdr) { 02606 if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED)) 02607 return cdr; 02608 cdr = cdr->next; 02609 } 02610 return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */ 02611 }
| static int play_message_in_bridged_call | ( | struct ast_channel * | caller_chan, | |
| struct ast_channel * | callee_chan, | |||
| const char * | audiofile | |||
| ) | [static] |
Play message to both caller and callee in bridged call, plays synchronously, autoservicing the other channel during the message, so please don't use this for very long messages.
Definition at line 1086 of file features.c.
References ast_autoservice_start(), ast_autoservice_stop(), ast_log(), ast_stream_and_wait(), and LOG_WARNING.
Referenced by builtin_automonitor().
01087 { 01088 /* First play for caller, put other channel on auto service */ 01089 if (ast_autoservice_start(callee_chan)) 01090 return -1; 01091 if (ast_stream_and_wait(caller_chan, audiofile, "")) { 01092 ast_log(LOG_WARNING, "Failed to play automon message!\n"); 01093 ast_autoservice_stop(callee_chan); 01094 return -1; 01095 } 01096 if (ast_autoservice_stop(callee_chan)) 01097 return -1; 01098 /* Then play for callee, put other channel on auto service */ 01099 if (ast_autoservice_start(caller_chan)) 01100 return -1; 01101 if (ast_stream_and_wait(callee_chan, audiofile, "")) { 01102 ast_log(LOG_WARNING, "Failed to play automon message !\n"); 01103 ast_autoservice_stop(caller_chan); 01104 return -1; 01105 } 01106 if (ast_autoservice_stop(caller_chan)) 01107 return -1; 01108 return(0); 01109 }
| static void post_manager_event | ( | const char * | s, | |
| struct parkeduser * | pu | |||
| ) | [static] |
Output parking event to manager.
Definition at line 3211 of file features.c.
References parkeduser::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, EVENT_FLAG_CALL, manager_event, ast_parkinglot::name, ast_channel::name, parkeduser::parkingexten, parkeduser::parkinglot, S_OR, and ast_channel::uniqueid.
Referenced by manage_parkinglot().
03212 { 03213 manager_event(EVENT_FLAG_CALL, s, 03214 "Exten: %s\r\n" 03215 "Channel: %s\r\n" 03216 "Parkinglot: %s\r\n" 03217 "CallerIDNum: %s\r\n" 03218 "CallerIDName: %s\r\n" 03219 "UniqueID: %s\r\n\r\n", 03220 pu->parkingexten, 03221 pu->chan->name, 03222 pu->parkinglot->name, 03223 S_OR(pu->chan->cid.cid_num, "<unknown>"), 03224 S_OR(pu->chan->cid.cid_name, "<unknown>"), 03225 pu->chan->uniqueid 03226 ); 03227 }
| static const char* real_ctx | ( | struct ast_channel * | transferer, | |
| struct ast_channel * | transferee | |||
| ) | [static] |
Find the context for the transfer.
| transferer | ||
| transferee | Grab the TRANSFER_CONTEXT, if fails try grabbing macrocontext. |
Definition at line 1349 of file 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().
01350 { 01351 const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"); 01352 if (ast_strlen_zero(s)) { 01353 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT"); 01354 } 01355 if (ast_strlen_zero(s)) { /* Use the non-macro context to transfer the call XXX ? */ 01356 s = transferer->macrocontext; 01357 } 01358 if (ast_strlen_zero(s)) { 01359 s = transferer->context; 01360 } 01361 return s; 01362 }
| static struct feature_group* register_group | ( | const char * | fgname | ) | [static, read] |
Add new feature group.
| fgname | feature group name. |
Definition at line 1930 of file features.c.
References ast_calloc, ast_free, AST_LIST_INSERT_HEAD, ast_log(), ast_string_field_init, ast_string_field_set, ast_verb, feature_group::gname, and LOG_NOTICE.
Referenced by load_config().
01931 { 01932 struct feature_group *fg; 01933 01934 if (!fgname) { 01935 ast_log(LOG_NOTICE, "You didn't pass a new group name!\n"); 01936 return NULL; 01937 } 01938 01939 if (!(fg = ast_calloc(1, sizeof(*fg)))) 01940 return NULL; 01941 01942 if (ast_string_field_init(fg, 128)) { 01943 ast_free(fg); 01944 return NULL; 01945 } 01946 01947 ast_string_field_set(fg, gname, fgname); 01948 01949 AST_LIST_INSERT_HEAD(&feature_groups, fg, entry); 01950 01951 ast_verb(2, "Registered group '%s'\n", fg->gname); 01952 01953 return fg; 01954 }
| static void register_group_feature | ( | struct feature_group * | fg, | |
| const char * | exten, | |||
| struct ast_call_feature * | feature | |||
| ) | [static] |
Add feature to group.
| fg | feature group | |
| exten | ||
| feature | feature to add. |
Definition at line 1965 of file features.c.
References ast_calloc, ast_free, AST_LIST_INSERT_HEAD, ast_log(), ast_string_field_init, ast_string_field_set, ast_verb, ast_call_feature::exten, feature_group_exten::feature, feature_group::features, feature_group::gname, LOG_NOTICE, S_OR, and ast_call_feature::sname.
Referenced by load_config().
01966 { 01967 struct feature_group_exten *fge; 01968 01969 if (!fg) { 01970 ast_log(LOG_NOTICE, "You didn't pass a group!\n"); 01971 return; 01972 } 01973 01974 if (!feature) { 01975 ast_log(LOG_NOTICE, "You didn't pass a feature!\n"); 01976 return; 01977 } 01978 01979 if (!(fge = ast_calloc(1, sizeof(*fge)))) 01980 return; 01981 01982 if (ast_string_field_init(fge, 128)) { 01983 ast_free(fge); 01984 return; 01985 } 01986 01987 ast_string_field_set(fge, exten, S_OR(exten, feature->exten)); 01988 01989 fge->feature = feature; 01990 01991 AST_LIST_INSERT_HEAD(&fg->features, fge, entry); 01992 01993 ast_verb(2, "Registered feature '%s' for group '%s' at exten '%s'\n", 01994 feature->sname, fg->gname, exten); 01995 }
| static int remap_feature | ( | const char * | name, | |
| const char * | value | |||
| ) | [static] |
Definition at line 2175 of file features.c.
References ast_copy_string(), ast_rwlock_unlock(), ast_rwlock_wrlock(), FEATURES_COUNT, and features_lock.
Referenced by load_config().
02176 { 02177 int x, res = -1; 02178 02179 ast_rwlock_wrlock(&features_lock); 02180 for (x = 0; x < FEATURES_COUNT; x++) { 02181 if (strcasecmp(builtin_features[x].sname, name)) 02182 continue; 02183 02184 ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten)); 02185 res = 0; 02186 break; 02187 } 02188 ast_rwlock_unlock(&features_lock); 02189 02190 return res; 02191 }
| static void set_bridge_features_on_config | ( | struct ast_bridge_config * | config, | |
| const char * | features | |||
| ) | [static] |
Definition at line 2613 of file features.c.
References AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, ast_log(), ast_set_flag, ast_strlen_zero(), ast_bridge_config::features_caller, and LOG_WARNING.
Referenced by ast_bridge_call().
02614 { 02615 const char *feature; 02616 02617 if (ast_strlen_zero(features)) { 02618 return; 02619 } 02620 02621 for (feature = features; *feature; feature++) { 02622 switch (*feature) { 02623 case 'T' : 02624 case 't' : 02625 ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT); 02626 break; 02627 case 'K' : 02628 case 'k' : 02629 ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL); 02630 break; 02631 case 'H' : 02632 case 'h' : 02633 ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT); 02634 break; 02635 case 'W' : 02636 case 'w' : 02637 ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON); 02638 break; 02639 default : 02640 ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature); 02641 } 02642 } 02643 }
| static void set_c_e_p | ( | struct ast_channel * | chan, | |
| const char * | context, | |||
| const char * | ext, | |||
| int | pri | |||
| ) | [static] |
store context, extension and priority
| chan,context,ext,pri |
Definition at line 467 of file features.c.
References ast_copy_string(), ast_channel::context, ast_channel::exten, and ast_channel::priority.
Referenced by builtin_blindtransfer(), manage_parkinglot(), and masq_park_call().
00468 { 00469 ast_copy_string(chan->context, context, sizeof(chan->context)); 00470 ast_copy_string(chan->exten, ext, sizeof(chan->exten)); 00471 chan->priority = pri; 00472 }
| static void set_config_flags | ( | struct ast_channel * | chan, | |
| struct ast_channel * | peer, | |||
| struct ast_bridge_config * | config | |||
| ) | [static] |
Definition at line 2341 of file 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_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_rwlock_rdlock(), ast_rwlock_unlock(), ast_set_flag, ast_strdupa, ast_test_flag, ast_call_feature::feature_mask, ast_bridge_config::features_callee, ast_bridge_config::features_caller, FEATURES_COUNT, features_lock, find_dynamic_feature(), pbx_builtin_getvar_helper(), and strsep()<