dial() & retrydial() - Trivial application to dial a channel and send an URL on answer More...
#include "asterisk.h"#include <sys/time.h>#include <sys/signal.h>#include <sys/stat.h>#include <netinet/in.h>#include "asterisk/paths.h"#include "asterisk/lock.h"#include "asterisk/file.h"#include "asterisk/channel.h"#include "asterisk/pbx.h"#include "asterisk/module.h"#include "asterisk/translate.h"#include "asterisk/say.h"#include "asterisk/config.h"#include "asterisk/features.h"#include "asterisk/musiconhold.h"#include "asterisk/callerid.h"#include "asterisk/utils.h"#include "asterisk/app.h"#include "asterisk/causes.h"#include "asterisk/rtp.h"#include "asterisk/cdr.h"#include "asterisk/manager.h"#include "asterisk/privacy.h"#include "asterisk/stringfields.h"#include "asterisk/global_datastores.h"#include "asterisk/dsp.h"
Go to the source code of this file.
Data Structures | |
| struct | cause_args |
| struct | chanlist |
| List of channel drivers. More... | |
| struct | privacy_args |
Defines | |
| #define | AST_MAX_WATCHERS 256 |
| #define | CAN_EARLY_BRIDGE(flags, chan, peer) |
| #define | DIAL_NOFORWARDHTML ((uint64_t)1 << 32) |
| #define | DIAL_STILLGOING (1 << 31) |
| #define | OPT_CALLEE_GO_ON ((uint64_t)1 << 35) |
| #define | OPT_CANCEL_ELSEWHERE ((uint64_t)1 << 33) |
| #define | OPT_PEER_H ((uint64_t)1 << 34) |
| #define | S_REPLACE(s, new_val) |
Enumerations | |
| enum | { OPT_ARG_ANNOUNCE = 0, OPT_ARG_SENDDTMF, OPT_ARG_GOTO, OPT_ARG_DURATION_LIMIT, OPT_ARG_MUSICBACK, OPT_ARG_CALLEE_MACRO, OPT_ARG_CALLEE_GOSUB, OPT_ARG_CALLEE_GO_ON, OPT_ARG_PRIVACY, OPT_ARG_DURATION_STOP, OPT_ARG_OPERMODE, OPT_ARG_SCREEN_NOINTRO, OPT_ARG_ARRAY_SIZE } |
| enum | { OPT_ANNOUNCE = (1 << 0), OPT_RESETCDR = (1 << 1), OPT_DTMF_EXIT = (1 << 2), OPT_SENDDTMF = (1 << 3), OPT_FORCECLID = (1 << 4), OPT_GO_ON = (1 << 5), OPT_CALLEE_HANGUP = (1 << 6), OPT_CALLER_HANGUP = (1 << 7), OPT_DURATION_LIMIT = (1 << 9), OPT_MUSICBACK = (1 << 10), OPT_CALLEE_MACRO = (1 << 11), OPT_SCREEN_NOINTRO = (1 << 12), OPT_SCREEN_NOCLID = (1 << 13), OPT_ORIGINAL_CLID = (1 << 14), OPT_SCREENING = (1 << 15), OPT_PRIVACY = (1 << 16), OPT_RINGBACK = (1 << 17), OPT_DURATION_STOP = (1 << 18), OPT_CALLEE_TRANSFER = (1 << 19), OPT_CALLER_TRANSFER = (1 << 20), OPT_CALLEE_MONITOR = (1 << 21), OPT_CALLER_MONITOR = (1 << 22), OPT_GOTO = (1 << 23), OPT_OPERMODE = (1 << 24), OPT_CALLEE_PARK = (1 << 25), OPT_CALLER_PARK = (1 << 26), OPT_IGNORE_FORWARDING = (1 << 27), OPT_CALLEE_GOSUB = (1 << 28), OPT_CALLEE_MIXMONITOR = (1 << 29), OPT_CALLER_MIXMONITOR = (1 << 30) } |
Functions | |
| static void | __reg_module (void) |
| static void | __unreg_module (void) |
| static int | dial_exec (struct ast_channel *chan, void *data) |
| static int | dial_exec_full (struct ast_channel *chan, void *data, struct ast_flags64 *peerflags, int *continue_exec) |
| static void | do_forward (struct chanlist *o, struct cause_args *num, struct ast_flags64 *peerflags, int single) |
| static int | do_timelimit (struct ast_channel *chan, struct ast_bridge_config *config, char *parse, struct timeval *calldurationlimit) |
| static void | end_bridge_callback (void *data) |
| static void | end_bridge_callback_data_fixup (struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator) |
| static const char * | get_cid_name (char *name, int namelen, struct ast_channel *chan) |
| static void | handle_cause (int cause, struct cause_args *num) |
| static void | hanguptree (struct chanlist *outgoing, struct ast_channel *exception, int answered_elsewhere) |
| static int | load_module (void) |
| static int | onedigit_goto (struct ast_channel *chan, const char *context, char exten, int pri) |
| static void | replace_macro_delimiter (char *s) |
| static int | retrydial_exec (struct ast_channel *chan, void *data) |
| static void | senddialendevent (const struct ast_channel *src, const char *dialstatus) |
| static void | senddialevent (struct ast_channel *src, struct ast_channel *dst, const char *dialstring) |
| static int | setup_privacy_args (struct privacy_args *pa, struct ast_flags64 *opts, char *opt_args[], struct ast_channel *chan) |
| returns 1 if successful, 0 or <0 if the caller should 'goto out' | |
| static int | unload_module (void) |
| static int | valid_priv_reply (struct ast_flags64 *opts, int res) |
| static struct ast_channel * | wait_for_answer (struct ast_channel *in, struct chanlist *outgoing, int *to, struct ast_flags64 *peerflags, struct privacy_args *pa, const struct cause_args *num_in, int *result) |
Variables | |
| static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Dialing Application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, } |
| static char * | app = "Dial" |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static struct ast_app_option | dial_exec_options [128] = { [ 'A' ] = { .flag = OPT_ANNOUNCE , .arg_index = OPT_ARG_ANNOUNCE + 1 }, [ 'C' ] = { .flag = OPT_RESETCDR }, [ 'c' ] = { .flag = ((uint64_t)1 << 33) }, [ 'd' ] = { .flag = OPT_DTMF_EXIT }, [ 'D' ] = { .flag = OPT_SENDDTMF , .arg_index = OPT_ARG_SENDDTMF + 1 }, [ 'e' ] = { .flag = ((uint64_t)1 << 34) }, [ 'f' ] = { .flag = OPT_FORCECLID }, [ 'F' ] = { .flag = ((uint64_t)1 << 35) , .arg_index = OPT_ARG_CALLEE_GO_ON + 1 }, [ 'g' ] = { .flag = OPT_GO_ON }, [ 'G' ] = { .flag = OPT_GOTO , .arg_index = OPT_ARG_GOTO + 1 }, [ 'h' ] = { .flag = OPT_CALLEE_HANGUP }, [ 'H' ] = { .flag = OPT_CALLER_HANGUP }, [ 'i' ] = { .flag = OPT_IGNORE_FORWARDING }, [ 'k' ] = { .flag = OPT_CALLEE_PARK }, [ 'K' ] = { .flag = OPT_CALLER_PARK }, [ 'L' ] = { .flag = OPT_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, [ 'm' ] = { .flag = OPT_MUSICBACK , .arg_index = OPT_ARG_MUSICBACK + 1 }, [ 'M' ] = { .flag = OPT_CALLEE_MACRO , .arg_index = OPT_ARG_CALLEE_MACRO + 1 }, [ 'n' ] = { .flag = OPT_SCREEN_NOINTRO , .arg_index = OPT_ARG_SCREEN_NOINTRO + 1 }, [ 'N' ] = { .flag = OPT_SCREEN_NOCLID }, [ 'o' ] = { .flag = OPT_ORIGINAL_CLID }, [ 'O' ] = { .flag = OPT_OPERMODE , .arg_index = OPT_ARG_OPERMODE + 1 }, [ 'p' ] = { .flag = OPT_SCREENING }, [ 'P' ] = { .flag = OPT_PRIVACY , .arg_index = OPT_ARG_PRIVACY + 1 }, [ 'r' ] = { .flag = OPT_RINGBACK }, [ 'S' ] = { .flag = OPT_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 't' ] = { .flag = OPT_CALLEE_TRANSFER }, [ 'T' ] = { .flag = OPT_CALLER_TRANSFER }, [ 'U' ] = { .flag = OPT_CALLEE_GOSUB , .arg_index = OPT_ARG_CALLEE_GOSUB + 1 }, [ 'w' ] = { .flag = OPT_CALLEE_MONITOR }, [ 'W' ] = { .flag = OPT_CALLER_MONITOR }, [ 'x' ] = { .flag = OPT_CALLEE_MIXMONITOR }, [ 'X' ] = { .flag = OPT_CALLER_MIXMONITOR }, } |
| static char * | rapp = "RetryDial" |
dial() & retrydial() - Trivial application to dial a channel and send an URL on answer
Definition in file app_dial.c.
| #define AST_MAX_WATCHERS 256 |
Definition at line 595 of file app_dial.c.
Referenced by monitor_dial(), and wait_for_answer().
| #define CAN_EARLY_BRIDGE | ( | flags, | |||
| chan, | |||||
| peer | ) |
(!ast_test_flag64(flags, OPT_CALLEE_HANGUP | \ OPT_CALLER_HANGUP | OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER | \ OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR | OPT_CALLEE_PARK | \ OPT_CALLER_PARK | OPT_ANNOUNCE | OPT_CALLEE_MACRO | OPT_CALLEE_GOSUB) && \ !chan->audiohooks && !peer->audiohooks)
Definition at line 558 of file app_dial.c.
Referenced by dial_exec_full(), do_forward(), and wait_for_answer().
| #define DIAL_NOFORWARDHTML ((uint64_t)1 << 32) |
Definition at line 500 of file app_dial.c.
Referenced by dial_exec_full(), and wait_for_answer().
| #define DIAL_STILLGOING (1 << 31) |
Definition at line 499 of file app_dial.c.
Referenced by dial_exec_full(), do_forward(), and wait_for_answer().
| #define OPT_CALLEE_GO_ON ((uint64_t)1 << 35) |
Definition at line 503 of file app_dial.c.
Referenced by dial_exec_full().
| #define OPT_CANCEL_ELSEWHERE ((uint64_t)1 << 33) |
Definition at line 501 of file app_dial.c.
Referenced by dial_exec_full().
| #define OPT_PEER_H ((uint64_t)1 << 34) |
Definition at line 502 of file app_dial.c.
Referenced by dial_exec_full().
| #define S_REPLACE | ( | s, | |||
| new_val | ) |
Definition at line 646 of file app_dial.c.
Referenced by begin_dial_channel(), dial_exec_full(), and do_forward().
| anonymous enum |
Definition at line 505 of file app_dial.c.
00505 { 00506 OPT_ARG_ANNOUNCE = 0, 00507 OPT_ARG_SENDDTMF, 00508 OPT_ARG_GOTO, 00509 OPT_ARG_DURATION_LIMIT, 00510 OPT_ARG_MUSICBACK, 00511 OPT_ARG_CALLEE_MACRO, 00512 OPT_ARG_CALLEE_GOSUB, 00513 OPT_ARG_CALLEE_GO_ON, 00514 OPT_ARG_PRIVACY, 00515 OPT_ARG_DURATION_STOP, 00516 OPT_ARG_OPERMODE, 00517 OPT_ARG_SCREEN_NOINTRO, 00518 /* note: this entry _MUST_ be the last one in the enum */ 00519 OPT_ARG_ARRAY_SIZE, 00520 };
| anonymous enum |
Definition at line 466 of file app_dial.c.
00466 { 00467 OPT_ANNOUNCE = (1 << 0), 00468 OPT_RESETCDR = (1 << 1), 00469 OPT_DTMF_EXIT = (1 << 2), 00470 OPT_SENDDTMF = (1 << 3), 00471 OPT_FORCECLID = (1 << 4), 00472 OPT_GO_ON = (1 << 5), 00473 OPT_CALLEE_HANGUP = (1 << 6), 00474 OPT_CALLER_HANGUP = (1 << 7), 00475 OPT_DURATION_LIMIT = (1 << 9), 00476 OPT_MUSICBACK = (1 << 10), 00477 OPT_CALLEE_MACRO = (1 << 11), 00478 OPT_SCREEN_NOINTRO = (1 << 12), 00479 OPT_SCREEN_NOCLID = (1 << 13), 00480 OPT_ORIGINAL_CLID = (1 << 14), 00481 OPT_SCREENING = (1 << 15), 00482 OPT_PRIVACY = (1 << 16), 00483 OPT_RINGBACK = (1 << 17), 00484 OPT_DURATION_STOP = (1 << 18), 00485 OPT_CALLEE_TRANSFER = (1 << 19), 00486 OPT_CALLER_TRANSFER = (1 << 20), 00487 OPT_CALLEE_MONITOR = (1 << 21), 00488 OPT_CALLER_MONITOR = (1 << 22), 00489 OPT_GOTO = (1 << 23), 00490 OPT_OPERMODE = (1 << 24), 00491 OPT_CALLEE_PARK = (1 << 25), 00492 OPT_CALLER_PARK = (1 << 26), 00493 OPT_IGNORE_FORWARDING = (1 << 27), 00494 OPT_CALLEE_GOSUB = (1 << 28), 00495 OPT_CALLEE_MIXMONITOR = (1 << 29), 00496 OPT_CALLER_MIXMONITOR = (1 << 30), 00497 };
| static void __reg_module | ( | void | ) | [static] |
Definition at line 2486 of file app_dial.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 2486 of file app_dial.c.
| static int dial_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 2336 of file app_dial.c.
References dial_exec_full().
Referenced by load_module().
02337 { 02338 struct ast_flags64 peerflags; 02339 02340 memset(&peerflags, 0, sizeof(peerflags)); 02341 02342 return dial_exec_full(chan, data, &peerflags, NULL); 02343 }
| static int dial_exec_full | ( | struct ast_channel * | chan, | |
| void * | data, | |||
| struct ast_flags64 * | peerflags, | |||
| int * | continue_exec | |||
| ) | [static] |
Definition at line 1515 of file app_dial.c.
References __ast_answer(), ast_channel::_state, ast_channel::accountcode, accountcode, ast_channel::adsicpe, ast_channel::appl, asprintf, AST_APP_ARG, ast_app_group_set_channel(), ast_app_parse_options64(), ast_autoservice_start(), ast_autoservice_stop(), ast_bridge_call(), ast_call(), ast_calloc, ast_cause2str(), AST_CAUSE_INVALID_NUMBER_FORMAT, ast_cdr_reset(), ast_cdr_setdestchan(), ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_datastore_inherit(), ast_channel_datastore_remove(), ast_channel_early_bridge(), ast_channel_inherit_variables(), ast_channel_lock, ast_channel_make_compatible(), ast_channel_sendurl(), ast_channel_setoption(), ast_channel_supports_html(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, AST_CONTROL_HANGUP, AST_CONTROL_PROGRESS, AST_CONTROL_RINGING, ast_copy_flags64, ast_copy_string(), ast_datastore_alloc, ast_datastore_free(), ast_deactivate_generator(), ast_debug, AST_DECLARE_APP_ARGS, AST_DIGIT_ANY, ast_dtmf_stream(), ast_exists_extension(), AST_FEATURE_AUTOMIXMON, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_NO_H_EXTEN, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, ast_filedelete(), ast_fileexists(), AST_FLAG_ANSWERED_ELSEWHERE, AST_FLAG_END_DTMF_ONLY, AST_FLAG_IN_AUTOLOOP, AST_FRAME_CONTROL, AST_FRAME_DTMF_END, ast_free, ast_frfree, ast_hangup(), ast_indicate(), AST_LIST_HEAD, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_EXTENSION, ast_moh_start(), ast_moh_stop(), AST_OPTION_OPRMODE, ast_parseable_goto(), AST_PBX_INCOMPLETE, ast_pbx_run_args(), ast_pbx_start(), AST_PRIVACY_UNKNOWN, ast_read(), ast_request(), ast_rtp_make_compatible(), ast_sched_runq(), ast_sched_wait(), ast_senddigit(), ast_set2_flag, ast_set2_flag64, ast_set_callerid(), ast_set_flag, ast_set_flag64, ast_spawn_extension(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_stopstream(), ast_strdup, ast_streamfile(), ast_string_field_set, ast_strlen_zero(), ast_test_flag, ast_test_flag64, ast_tvadd(), ast_tvnow(), ast_tvzero(), ast_verb, ast_waitfor_n(), CAN_EARLY_BRIDGE, cause, ast_channel::cdr, ast_channel::cdrflags, chanlist::chan, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_ani2, ast_callerid::cid_name, ast_callerid::cid_num, ast_callerid::cid_pres, ast_callerid::cid_rdnis, ast_callerid::cid_tns, ast_callerid::cid_ton, ast_channel::context, ast_channel::data, ast_datastore::data, DATASTORE_INHERIT_FOREVER, di, dial_exec_options, DIAL_NOFORWARDHTML, DIAL_STILLGOING, dialcontext, dialed_interface_info, do_timelimit(), end_bridge_callback(), ast_bridge_config::end_bridge_callback, ast_bridge_config::end_bridge_callback_data, end_bridge_callback_data_fixup(), ast_bridge_config::end_bridge_callback_data_fixup, ast_bridge_config::end_sound, errno, ast_channel::exten, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_flags64::flags, ast_frame::frametype, get_cid_name(), handle_cause(), ast_channel::hangupcause, hanguptree(), ast_datastore::inheritance, ast_dialed_interface::interface, ast_channel::language, ast_dialed_interface::list, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_channel::macrocontext, ast_channel::macroexten, oprmode::mode, moh, musicclass, ast_channel::musicclass, ast_channel::name, ast_channel::nativeformats, chanlist::next, ast_pbx_args::no_hangup_chan, OPT_ANNOUNCE, OPT_ARG_ANNOUNCE, OPT_ARG_ARRAY_SIZE, OPT_ARG_CALLEE_GO_ON, OPT_ARG_CALLEE_GOSUB, OPT_ARG_CALLEE_MACRO, OPT_ARG_DURATION_LIMIT, OPT_ARG_DURATION_STOP, OPT_ARG_GOTO, OPT_ARG_OPERMODE, OPT_ARG_PRIVACY, OPT_ARG_SCREEN_NOINTRO, OPT_ARG_SENDDTMF, OPT_CALLEE_GO_ON, OPT_CALLEE_GOSUB, OPT_CALLEE_HANGUP, OPT_CALLEE_MACRO, OPT_CALLEE_MIXMONITOR, OPT_CALLEE_MONITOR, OPT_CALLEE_PARK, OPT_CALLEE_TRANSFER, OPT_CALLER_HANGUP, OPT_CALLER_MIXMONITOR, OPT_CALLER_MONITOR, OPT_CALLER_PARK, OPT_CALLER_TRANSFER, OPT_CANCEL_ELSEWHERE, OPT_DTMF_EXIT, OPT_DURATION_LIMIT, OPT_DURATION_STOP, OPT_FORCECLID, OPT_GO_ON, OPT_GOTO, OPT_IGNORE_FORWARDING, OPT_MUSICBACK, OPT_OPERMODE, OPT_ORIGINAL_CLID, OPT_PEER_H, OPT_PRIVACY, OPT_RESETCDR, OPT_RINGBACK, OPT_SCREEN_NOINTRO, OPT_SCREENING, OPT_SENDDTMF, parse(), pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), oprmode::peer, ast_channel::priority, privacy_args::privdb_val, privacy_args::privintro, replace_macro_delimiter(), S_OR, S_REPLACE, ast_channel::sched, senddialendevent(), senddialevent(), privacy_args::sentringing, setup_privacy_args(), ast_bridge_config::start_sound, privacy_args::status, ast_channel::stream, ast_frame::subclass, ast_channel::tech, ast_channel::timingfunc, ast_channel::transfercapability, url, wait_for_answer(), ast_bridge_config::warning_sound, and ast_channel::whentohangup.
Referenced by dial_exec(), and retrydial_exec().
01516 { 01517 int res = -1; /* default: error */ 01518 char *rest, *cur; /* scan the list of destinations */ 01519 struct chanlist *outgoing = NULL; /* list of destinations */ 01520 struct ast_channel *peer; 01521 int to; /* timeout */ 01522 struct cause_args num = { chan, 0, 0, 0 }; 01523 int cause; 01524 char numsubst[256]; 01525 char cidname[AST_MAX_EXTENSION] = ""; 01526 01527 struct ast_bridge_config config = { { 0, } }; 01528 struct timeval calldurationlimit = { 0, }; 01529 char *dtmfcalled = NULL, *dtmfcalling = NULL; 01530 struct privacy_args pa = { 01531 .sentringing = 0, 01532 .privdb_val = 0, 01533 .status = "INVALIDARGS", 01534 }; 01535 int sentringing = 0, moh = 0; 01536 const char *outbound_group = NULL; 01537 int result = 0; 01538 char *parse; 01539 int opermode = 0; 01540 int delprivintro = 0; 01541 AST_DECLARE_APP_ARGS(args, 01542 AST_APP_ARG(peers); 01543 AST_APP_ARG(timeout); 01544 AST_APP_ARG(options); 01545 AST_APP_ARG(url); 01546 ); 01547 struct ast_flags64 opts = { 0, }; 01548 char *opt_args[OPT_ARG_ARRAY_SIZE]; 01549 struct ast_datastore *datastore = NULL; 01550 int fulldial = 0, num_dialed = 0; 01551 01552 /* Reset all DIAL variables back to blank, to prevent confusion (in case we don't reset all of them). */ 01553 pbx_builtin_setvar_helper(chan, "DIALSTATUS", ""); 01554 pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", ""); 01555 pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", ""); 01556 pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", ""); 01557 pbx_builtin_setvar_helper(chan, "DIALEDTIME", ""); 01558 01559 if (ast_strlen_zero(data)) { 01560 ast_log(LOG_WARNING, "Dial requires an argument (technology/number)\n"); 01561 pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status); 01562 return -1; 01563 } 01564 01565 parse = ast_strdupa(data); 01566 01567 AST_STANDARD_APP_ARGS(args, parse); 01568 01569 if (!ast_strlen_zero(args.options) && 01570 ast_app_parse_options64(dial_exec_options, &opts, opt_args, args.options)) { 01571 pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status); 01572 goto done; 01573 } 01574 01575 if (ast_strlen_zero(args.peers)) { 01576 ast_log(LOG_WARNING, "Dial requires an argument (technology/number)\n"); 01577 pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status); 01578 goto done; 01579 } 01580 01581 01582 if (ast_test_flag64(&opts, OPT_SCREEN_NOINTRO) && !ast_strlen_zero(opt_args[OPT_ARG_SCREEN_NOINTRO])) { 01583 delprivintro = atoi(opt_args[OPT_ARG_SCREEN_NOINTRO]); 01584 01585 if (delprivintro < 0 || delprivintro > 1) { 01586 ast_log(LOG_WARNING, "Unknown argument %d specified to n option, ignoring\n", delprivintro); 01587 delprivintro = 0; 01588 } 01589 } 01590 01591 if (ast_test_flag64(&opts, OPT_OPERMODE)) { 01592 opermode = ast_strlen_zero(opt_args[OPT_ARG_OPERMODE]) ? 1 : atoi(opt_args[OPT_ARG_OPERMODE]); 01593 ast_verb(3, "Setting operator services mode to %d.\n", opermode); 01594 } 01595 01596 if (ast_test_flag64(&opts, OPT_DURATION_STOP) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_STOP])) { 01597 calldurationlimit.tv_sec = atoi(opt_args[OPT_ARG_DURATION_STOP]); 01598 if (!calldurationlimit.tv_sec) { 01599 ast_log(LOG_WARNING, "Dial does not accept S(%s), hanging up.\n", opt_args[OPT_ARG_DURATION_STOP]); 01600 pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status); 01601 goto done; 01602 } 01603 ast_verb(3, "Setting call duration limit to %.3lf seconds.\n", calldurationlimit.tv_sec + calldurationlimit.tv_usec / 1000000.0); 01604 } 01605 01606 if (ast_test_flag64(&opts, OPT_SENDDTMF) && !ast_strlen_zero(opt_args[OPT_ARG_SENDDTMF])) { 01607 dtmfcalling = opt_args[OPT_ARG_SENDDTMF]; 01608 dtmfcalled = strsep(&dtmfcalling, ":"); 01609 } 01610 01611 if (ast_test_flag64(&opts, OPT_DURATION_LIMIT) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])) { 01612 if (do_timelimit(chan, &config, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit)) 01613 goto done; 01614 } 01615 01616 if (ast_test_flag64(&opts, OPT_RESETCDR) && chan->cdr) 01617 ast_cdr_reset(chan->cdr, NULL); 01618 if (ast_test_flag64(&opts, OPT_PRIVACY) && ast_strlen_zero(opt_args[OPT_ARG_PRIVACY])) 01619 opt_args[OPT_ARG_PRIVACY] = ast_strdupa(chan->exten); 01620 01621 if (ast_test_flag64(&opts, OPT_PRIVACY) || ast_test_flag64(&opts, OPT_SCREENING)) { 01622 res = setup_privacy_args(&pa, &opts, opt_args, chan); 01623 if (res <= 0) 01624 goto out; 01625 res = -1; /* reset default */ 01626 } 01627 01628 if (ast_test_flag64(&opts, OPT_DTMF_EXIT)) { 01629 __ast_answer(chan, 0, 0); 01630 } 01631 01632 if (continue_exec) 01633 *continue_exec = 0; 01634 01635 /* If a channel group has been specified, get it for use when we create peer channels */ 01636 01637 ast_channel_lock(chan); 01638 if ((outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP_ONCE"))) { 01639 outbound_group = ast_strdupa(outbound_group); 01640 pbx_builtin_setvar_helper(chan, "OUTBOUND_GROUP_ONCE", NULL); 01641 } else if ((outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP"))) { 01642 outbound_group = ast_strdupa(outbound_group); 01643 } 01644 ast_channel_unlock(chan); 01645 ast_copy_flags64(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING | OPT_ANNOUNCE | OPT_CALLEE_MACRO | OPT_CALLEE_GOSUB); 01646 01647 /* loop through the list of dial destinations */ 01648 rest = args.peers; 01649 while ((cur = strsep(&rest, "&")) ) { 01650 struct chanlist *tmp; 01651 struct ast_channel *tc; /* channel for this destination */ 01652 /* Get a technology/[device:]number pair */ 01653 char *number = cur; 01654 char *interface = ast_strdupa(number); 01655 char *tech = strsep(&number, "/"); 01656 /* find if we already dialed this interface */ 01657 struct ast_dialed_interface *di; 01658 AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces; 01659 num_dialed++; 01660 if (!number) { 01661 ast_log(LOG_WARNING, "Dial argument takes format (technology/[device:]number1)\n"); 01662 goto out; 01663 } 01664 if (!(tmp = ast_calloc(1, sizeof(*tmp)))) 01665 goto out; 01666 if (opts.flags) { 01667 ast_copy_flags64(tmp, &opts, 01668 OPT_CANCEL_ELSEWHERE | 01669 OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER | 01670 OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP | 01671 OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR | 01672 OPT_CALLEE_PARK | OPT_CALLER_PARK | 01673 OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR | 01674 OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID); 01675 ast_set2_flag64(tmp, args.url, DIAL_NOFORWARDHTML); 01676 } 01677 ast_copy_string(numsubst, number, sizeof(numsubst)); 01678 /* Request the peer */ 01679 01680 ast_channel_lock(chan); 01681 datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL); 01682 ast_channel_unlock(chan); 01683 01684 if (datastore) 01685 dialed_interfaces = datastore->data; 01686 else { 01687 if (!(datastore = ast_datastore_alloc(&dialed_interface_info, NULL))) { 01688 ast_log(LOG_WARNING, "Unable to create channel datastore for dialed interfaces. Aborting!\n"); 01689 ast_free(tmp); 01690 goto out; 01691 } 01692 01693 datastore->inheritance = DATASTORE_INHERIT_FOREVER; 01694 01695 if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) { 01696 ast_datastore_free(datastore); 01697 ast_free(tmp); 01698 goto out; 01699 } 01700 01701 datastore->data = dialed_interfaces; 01702 AST_LIST_HEAD_INIT(dialed_interfaces); 01703 01704 ast_channel_lock(chan); 01705 ast_channel_datastore_add(chan, datastore); 01706 ast_channel_unlock(chan); 01707 } 01708 01709 AST_LIST_LOCK(dialed_interfaces); 01710 AST_LIST_TRAVERSE(dialed_interfaces, di, list) { 01711 if (!strcasecmp(di->interface, interface)) { 01712 ast_log(LOG_WARNING, "Skipping dialing interface '%s' again since it has already been dialed\n", 01713 di->interface); 01714 break; 01715 } 01716 } 01717 AST_LIST_UNLOCK(dialed_interfaces); 01718 01719 if (di) { 01720 fulldial++; 01721 ast_free(tmp); 01722 continue; 01723 } 01724 01725 /* It is always ok to dial a Local interface. We only keep track of 01726 * which "real" interfaces have been dialed. The Local channel will 01727 * inherit this list so that if it ends up dialing a real interface, 01728 * it won't call one that has already been called. */ 01729 if (strcasecmp(tech, "Local")) { 01730 if (!(di = ast_calloc(1, sizeof(*di) + strlen(interface)))) { 01731 AST_LIST_UNLOCK(dialed_interfaces); 01732 ast_free(tmp); 01733 goto out; 01734 } 01735 strcpy(di->interface, interface); 01736 01737 AST_LIST_LOCK(dialed_interfaces); 01738 AST_LIST_INSERT_TAIL(dialed_interfaces, di, list); 01739 AST_LIST_UNLOCK(dialed_interfaces); 01740 } 01741 01742 tc = ast_request(tech, chan->nativeformats, numsubst, &cause); 01743 if (!tc) { 01744 /* If we can't, just go on to the next call */ 01745 ast_log(LOG_WARNING, "Unable to create channel of type '%s' (cause %d - %s)\n", 01746 tech, cause, ast_cause2str(cause)); 01747 handle_cause(cause, &num); 01748 if (!rest) /* we are on the last destination */ 01749 chan->hangupcause = cause; 01750 ast_free(tmp); 01751 continue; 01752 } 01753 pbx_builtin_setvar_helper(tc, "DIALEDPEERNUMBER", numsubst); 01754 01755 /* Setup outgoing SDP to match incoming one */ 01756 if (CAN_EARLY_BRIDGE(peerflags, chan, tc)) { 01757 ast_rtp_make_compatible(tc, chan, !outgoing && !rest); 01758 } 01759 01760 /* Inherit specially named variables from parent channel */ 01761 ast_channel_inherit_variables(chan, tc); 01762 ast_channel_datastore_inherit(chan, tc); 01763 01764 tc->appl = "AppDial"; 01765 tc->data = "(Outgoing Line)"; 01766 memset(&tc->whentohangup, 0, sizeof(tc->whentohangup)); 01767 01768 S_REPLACE(tc->cid.cid_num, ast_strdup(chan->cid.cid_num)); 01769 S_REPLACE(tc->cid.cid_name, ast_strdup(chan->cid.cid_name)); 01770 S_REPLACE(tc->cid.cid_ani, ast_strdup(chan->cid.cid_ani)); 01771 S_REPLACE(tc->cid.cid_rdnis, ast_strdup(chan->cid.cid_rdnis)); 01772 01773 ast_string_field_set(tc, accountcode, chan->accountcode); 01774 tc->cdrflags = chan->cdrflags; 01775 if (ast_strlen_zero(tc->musicclass)) 01776 ast_string_field_set(tc, musicclass, chan->musicclass); 01777 /* Pass callingpres, type of number, tns, ADSI CPE, transfer capability */ 01778 tc->cid.cid_pres = chan->cid.cid_pres; 01779 tc->cid.cid_ton = chan->cid.cid_ton; 01780 tc->cid.cid_tns = chan->cid.cid_tns; 01781 tc->cid.cid_ani2 = chan->cid.cid_ani2; 01782 tc->adsicpe = chan->adsicpe; 01783 tc->transfercapability = chan->transfercapability; 01784 01785 /* If we have an outbound group, set this peer channel to it */ 01786 if (outbound_group) 01787 ast_app_group_set_channel(tc, outbound_group); 01788 /* If the calling channel has the ANSWERED_ELSEWHERE flag set, inherit it. This is to support local channels */ 01789 if (ast_test_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE)) 01790 ast_set_flag(tc, AST_FLAG_ANSWERED_ELSEWHERE); 01791 01792 /* Check if we're forced by configuration */ 01793 if (ast_test_flag64(&opts, OPT_CANCEL_ELSEWHERE)) 01794 ast_set_flag(tc, AST_FLAG_ANSWERED_ELSEWHERE); 01795 01796 01797 /* Inherit context and extension */ 01798 ast_string_field_set(tc, dialcontext, ast_strlen_zero(chan->macrocontext) ? chan->context : chan->macrocontext); 01799 if (!ast_strlen_zero(chan->macroexten)) 01800 ast_copy_string(tc->exten, chan->macroexten, sizeof(tc->exten)); 01801 else 01802 ast_copy_string(tc->exten, chan->exten, sizeof(tc->exten)); 01803 01804 res = ast_call(tc, numsubst, 0); /* Place the call, but don't wait on the answer */ 01805 01806 /* Save the info in cdr's that we called them */ 01807 if (chan->cdr) 01808 ast_cdr_setdestchan(chan->cdr, tc->name); 01809 01810 /* check the results of ast_call */ 01811 if (res) { 01812 /* Again, keep going even if there's an error */ 01813 ast_debug(1, "ast call on peer returned %d\n", res); 01814 ast_verb(3, "Couldn't call %s\n", numsubst); 01815 if (tc->hangupcause) { 01816 chan->hangupcause = tc->hangupcause; 01817 } 01818 ast_hangup(tc); 01819 tc = NULL; 01820 ast_free(tmp); 01821 continue; 01822 } else { 01823 senddialevent(chan, tc, numsubst); 01824 ast_verb(3, "Called %s\n", numsubst); 01825 if (!ast_test_flag64(peerflags, OPT_ORIGINAL_CLID)) 01826 ast_set_callerid(tc, S_OR(chan->macroexten, chan->exten), get_cid_name(cidname, sizeof(cidname), chan), NULL); 01827 } 01828 /* Put them in the list of outgoing thingies... We're ready now. 01829 XXX If we're forcibly removed, these outgoing calls won't get 01830 hung up XXX */ 01831 ast_set_flag64(tmp, DIAL_STILLGOING); 01832 tmp->chan = tc; 01833 tmp->next = outgoing; 01834 outgoing = tmp; 01835 /* If this line is up, don't try anybody else */ 01836 if (outgoing->chan->_state == AST_STATE_UP) 01837 break; 01838 } 01839 01840 if (ast_strlen_zero(args.timeout)) { 01841 to = -1; 01842 } else { 01843 to = atoi(args.timeout); 01844 if (to > 0) 01845 to *= 1000; 01846 else { 01847 ast_log(LOG_WARNING, "Invalid timeout specified: '%s'. Setting timeout to infinite\n", args.timeout); 01848 to = -1; 01849 } 01850 } 01851 01852 if (!outgoing) { 01853 strcpy(pa.status, "CHANUNAVAIL"); 01854 if (fulldial == num_dialed) { 01855 res = -1; 01856 goto out; 01857 } 01858 } else { 01859 /* Our status will at least be NOANSWER */ 01860 strcpy(pa.status, "NOANSWER"); 01861 if (ast_test_flag64(outgoing, OPT_MUSICBACK)) { 01862 moh = 1; 01863 if (!ast_strlen_zero(opt_args[OPT_ARG_MUSICBACK])) { 01864 char *original_moh = ast_strdupa(chan->musicclass); 01865 ast_string_field_set(chan, musicclass, opt_args[OPT_ARG_MUSICBACK]); 01866 ast_moh_start(chan, opt_args[OPT_ARG_MUSICBACK], NULL); 01867 ast_string_field_set(chan, musicclass, original_moh); 01868 } else { 01869 ast_moh_start(chan, NULL, NULL); 01870 } 01871 ast_indicate(chan, AST_CONTROL_PROGRESS); 01872 } else if (ast_test_flag64(outgoing, OPT_RINGBACK)) { 01873 ast_indicate(chan, AST_CONTROL_RINGING); 01874 sentringing++; 01875 } 01876 } 01877 01878 peer = wait_for_answer(chan, outgoing, &to, peerflags, &pa, &num, &result); 01879 01880 /* The ast_channel_datastore_remove() function could fail here if the 01881 * datastore was moved to another channel during a masquerade. If this is 01882 * the case, don't free the datastore here because later, when the channel 01883 * to which the datastore was moved hangs up, it will attempt to free this 01884 * datastore again, causing a crash 01885 */ 01886 if (!ast_channel_datastore_remove(chan, datastore)) 01887 ast_datastore_free(datastore); 01888 if (!peer) { 01889 if (result) { 01890 res = result; 01891 } else if (to) { /* Musta gotten hung up */ 01892 res = -1; 01893 } else { /* Nobody answered, next please? */ 01894 res = 0; 01895 } 01896 01897 /* SIP, in particular, sends back this error code to indicate an 01898 * overlap dialled number needs more digits. */ 01899 if (chan->hangupcause == AST_CAUSE_INVALID_NUMBER_FORMAT) { 01900 res = AST_PBX_INCOMPLETE; 01901 } 01902 01903 /* almost done, although the 'else' block is 400 lines */ 01904 } else { 01905 const char *number; 01906 01907 strcpy(pa.status, "ANSWER"); 01908 pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status); 01909 /* Ah ha! Someone answered within the desired timeframe. Of course after this 01910 we will always return with -1 so that it is hung up properly after the 01911 conversation. */ 01912 hanguptree(outgoing, peer, 1); 01913 outgoing = NULL; 01914 /* If appropriate, log that we have a destination channel */ 01915 if (chan->cdr) 01916 ast_cdr_setdestchan(chan->cdr, peer->name); 01917 if (peer->name) 01918 pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", peer->name); 01919 01920 ast_channel_lock(peer); 01921 number = pbx_builtin_getvar_helper(peer, "DIALEDPEERNUMBER"); 01922 if (!number) 01923 number = numsubst; 01924 pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", number); 01925 ast_channel_unlock(peer); 01926 01927 if (!ast_strlen_zero(args.url) && ast_channel_supports_html(peer) ) { 01928 ast_debug(1, "app_dial: sendurl=%s.\n", args.url); 01929 ast_channel_sendurl( peer, args.url ); 01930 } 01931 if ( (ast_test_flag64(&opts, OPT_PRIVACY) || ast_test_flag64(&opts, OPT_SCREENING)) && pa.privdb_val == AST_PRIVACY_UNKNOWN) { 01932 if (do_privacy(chan, peer, &opts, opt_args, &pa)) { 01933 res = 0; 01934 goto out; 01935 } 01936 } 01937 if (!ast_test_flag64(&opts, OPT_ANNOUNCE) || ast_strlen_zero(opt_args[OPT_ARG_ANNOUNCE])) { 01938 res = 0; 01939 } else { 01940 int digit = 0; 01941 struct ast_channel *chans[2]; 01942 struct ast_channel *active_chan; 01943 01944 chans[0] = chan; 01945 chans[1] = peer; 01946 01947 /* we need to stream the announcment while monitoring the caller for a hangup */ 01948 01949 /* stream the file */ 01950 res = ast_streamfile(peer, opt_args[OPT_ARG_ANNOUNCE], peer->language); 01951 if (res) { 01952 res = 0; 01953 ast_log(LOG_ERROR, "error streaming file '%s' to callee\n", opt_args[OPT_ARG_ANNOUNCE]); 01954 } 01955 01956 ast_set_flag(peer, AST_FLAG_END_DTMF_ONLY); 01957 while (peer->stream) { 01958 int ms; 01959 01960 ms = ast_sched_wait(peer->sched); 01961 01962 if (ms < 0 && !peer->timingfunc) { 01963 ast_stopstream(peer); 01964 break; 01965 } 01966 if (ms < 0) 01967 ms = 1000; 01968 01969 active_chan = ast_waitfor_n(chans, 2, &ms); 01970 if (active_chan) { 01971 struct ast_frame *fr = ast_read(active_chan); 01972 if (!fr) { 01973 ast_hangup(peer); 01974 res = -1; 01975 goto done; 01976 } 01977 switch(fr->frametype) { 01978 case AST_FRAME_DTMF_END: 01979 digit = fr->subclass; 01980 if (active_chan == peer && strchr(AST_DIGIT_ANY, res)) { 01981 ast_stopstream(peer); 01982 res = ast_senddigit(chan, digit, 0); 01983 } 01984 break; 01985 case AST_FRAME_CONTROL: 01986 switch (fr->subclass) { 01987 case AST_CONTROL_HANGUP: 01988 ast_frfree(fr); 01989 ast_hangup(peer); 01990 res = -1; 01991 goto done; 01992 default: 01993 break; 01994 } 01995 break; 01996 default: 01997 /* Ignore all others */ 01998 break; 01999 } 02000 ast_frfree(fr); 02001 } 02002 ast_sched_runq(peer->sched); 02003 } 02004 ast_clear_flag(peer, AST_FLAG_END_DTMF_ONLY); 02005 } 02006 02007 if (chan && peer && ast_test_flag64(&opts, OPT_GOTO) && !ast_strlen_zero(opt_args[OPT_ARG_GOTO])) { 02008 replace_macro_delimiter(opt_args[OPT_ARG_GOTO]); 02009 ast_parseable_goto(chan, opt_args[OPT_ARG_GOTO]); 02010 /* peer goes to the same context and extension as chan, so just copy info from chan*/ 02011 ast_copy_string(peer->context, chan->context, sizeof(peer->context)); 02012 ast_copy_string(peer->exten, chan->exten, sizeof(peer->exten)); 02013 peer->priority = chan->priority + 2; 02014 ast_pbx_start(peer); 02015 hanguptree(outgoing, NULL, ast_test_flag64(&opts, OPT_CANCEL_ELSEWHERE) ? 1 : 0); 02016 if (continue_exec) 02017 *continue_exec = 1; 02018 res = 0; 02019 goto done; 02020 } 02021 02022 if (ast_test_flag64(&opts, OPT_CALLEE_MACRO) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_MACRO])) { 02023 struct ast_app *theapp; 02024 const char *macro_result; 02025 02026 res = ast_autoservice_start(chan); 02027 if (res) { 02028 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n"); 02029 res = -1; 02030 } 02031 02032 theapp = pbx_findapp("Macro"); 02033 02034 if (theapp && !res) { /* XXX why check res here ? */ 02035 /* Set peer->exten and peer->context so that MACRO_EXTEN and MACRO_CONTEXT get set */ 02036 ast_copy_string(peer->context, chan->context, sizeof(peer->context)); 02037 ast_copy_string(peer->exten, chan->exten, sizeof(peer->exten)); 02038 02039 replace_macro_delimiter(opt_args[OPT_ARG_CALLEE_MACRO]); 02040 res = pbx_exec(peer, theapp, opt_args[OPT_ARG_CALLEE_MACRO]); 02041 ast_debug(1, "Macro exited with status %d\n", res); 02042 res = 0; 02043 } else { 02044 ast_log(LOG_ERROR, "Could not find application Macro\n"); 02045 res = -1; 02046 } 02047 02048 if (ast_autoservice_stop(chan) < 0) { 02049 res = -1; 02050 } 02051 02052 ast_channel_lock(peer); 02053 02054 if (!res && (macro_result = pbx_builtin_getvar_helper(peer, "MACRO_RESULT"))) { 02055 char *macro_transfer_dest; 02056 02057 if (!strcasecmp(macro_result, "BUSY")) { 02058 ast_copy_string(pa.status, macro_result, sizeof(pa.status)); 02059 ast_set_flag64(peerflags, OPT_GO_ON); 02060 res = -1; 02061 } else if (!strcasecmp(macro_result, "CONGESTION") || !strcasecmp(macro_result, "CHANUNAVAIL")) { 02062 ast_copy_string(pa.status, macro_result, sizeof(pa.status)); 02063 ast_set_flag64(peerflags, OPT_GO_ON); 02064 res = -1; 02065 } else if (!strcasecmp(macro_result, "CONTINUE")) { 02066 /* hangup peer and keep chan alive assuming the macro has changed 02067 the context / exten / priority or perhaps 02068 the next priority in the current exten is desired. 02069 */ 02070 ast_set_flag64(peerflags, OPT_GO_ON); 02071 res = -1; 02072 } else if (!strcasecmp(macro_result, "ABORT")) { 02073 /* Hangup both ends unless the caller has the g flag */ 02074 res = -1; 02075 } else if (!strncasecmp(macro_result, "GOTO:", 5) && (macro_transfer_dest = ast_strdupa(macro_result + 5))) { 02076 res = -1; 02077 /* perform a transfer to a new extension */ 02078 if (strchr(macro_transfer_dest, '^')) { /* context^exten^priority*/ 02079 replace_macro_delimiter(macro_transfer_dest); 02080 if (!ast_parseable_goto(chan, macro_transfer_dest)) 02081 ast_set_flag64(peerflags, OPT_GO_ON); 02082 } 02083 } 02084 } 02085 02086 ast_channel_unlock(peer); 02087 } 02088 02089 if (ast_test_flag64(&opts, OPT_CALLEE_GOSUB) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GOSUB])) { 02090 struct ast_app *theapp; 02091 const char *gosub_result; 02092 char *gosub_args, *gosub_argstart; 02093 int res9 = -1; 02094 02095 res9 = ast_autoservice_start(chan); 02096 if (res9) { 02097 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n"); 02098 res9 = -1; 02099 } 02100 02101 theapp = pbx_findapp("Gosub"); 02102 02103 if (theapp && !res9) { 02104 replace_macro_delimiter(opt_args[OPT_ARG_CALLEE_GOSUB]); 02105 02106 /* Set where we came from */ 02107 ast_copy_string(peer->context, "app_dial_gosub_virtual_context", sizeof(peer->context)); 02108 ast_copy_string(peer->exten, "s", sizeof(peer->exten)); 02109 peer->priority = 0; 02110 02111 gosub_argstart = strchr(opt_args[OPT_ARG_CALLEE_GOSUB], ','); 02112 if (gosub_argstart) { 02113 *gosub_argstart = 0; 02114 if (asprintf(&gosub_args, "%s,s,1(%s)", opt_args[OPT_ARG_CALLEE_GOSUB], gosub_argstart + 1) < 0) { 02115 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 02116 gosub_args = NULL; 02117 } 02118 *gosub_argstart = ','; 02119 } else { 02120 if (asprintf(&gosub_args, "%s,s,1", opt_args[OPT_ARG_CALLEE_GOSUB]) < 0) { 02121 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 02122 gosub_args = NULL; 02123 } 02124 } 02125 02126 if (gosub_args) { 02127 res9 = pbx_exec(peer, theapp, gosub_args); 02128 if (!res9) { 02129 struct ast_pbx_args args; 02130 /* A struct initializer fails to compile for this case ... */ 02131 memset(&args, 0, sizeof(args)); 02132 args.no_hangup_chan = 1; 02133 ast_pbx_run_args(peer, &args); 02134 } 02135 ast_free(gosub_args); 02136 ast_debug(1, "Gosub exited with status %d\n", res9); 02137 } else { 02138 ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n"); 02139 } 02140 02141 } else if (!res9) { 02142 ast_log(LOG_ERROR, "Could not find application Gosub\n"); 02143 res9 = -1; 02144 } 02145 02146 if (ast_autoservice_stop(chan) < 0) { 02147 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n"); 02148 res9 = -1; 02149 } 02150 02151 ast_channel_lock(peer); 02152 02153 if (!res9 && (gosub_result = pbx_builtin_getvar_helper(peer, "GOSUB_RESULT"))) { 02154 char *gosub_transfer_dest; 02155 02156 if (!strcasecmp(gosub_result, "BUSY")) { 02157 ast_copy_string(pa.status, gosub_result, sizeof(pa.status)); 02158 ast_set_flag64(peerflags, OPT_GO_ON); 02159 res = -1; 02160 } else if (!strcasecmp(gosub_result, "CONGESTION") || !strcasecmp(gosub_result, "CHANUNAVAIL")) { 02161 ast_copy_string(pa.status, gosub_result, sizeof(pa.status)); 02162 ast_set_flag64(peerflags, OPT_GO_ON); 02163 res = -1; 02164 } else if (!strcasecmp(gosub_result, "CONTINUE")) { 02165 /* hangup peer and keep chan alive assuming the macro has changed 02166 the context / exten / priority or perhaps 02167 the next priority in the current exten is desired. 02168 */ 02169 ast_set_flag64(peerflags, OPT_GO_ON); 02170 res = -1; 02171 } else if (!strcasecmp(gosub_result, "ABORT")) { 02172 /* Hangup both ends unless the caller has the g flag */ 02173 res = -1; 02174 } else if (!strncasecmp(gosub_result, "GOTO:", 5) && (gosub_transfer_dest = ast_strdupa(gosub_result + 5))) { 02175 res = -1; 02176 /* perform a transfer to a new extension */ 02177 if (strchr(gosub_transfer_dest, '^')) { /* context^exten^priority*/ 02178 replace_macro_delimiter(gosub_transfer_dest); 02179 if (!ast_parseable_goto(chan, gosub_transfer_dest)) 02180 ast_set_flag64(peerflags, OPT_GO_ON); 02181 } 02182 } 02183 } 02184 02185 ast_channel_unlock(peer); 02186 } 02187 02188 if (!res) { 02189 if (!ast_tvzero(calldurationlimit)) { 02190 struct timeval whentohangup = calldurationlimit; 02191 peer->whentohangup = ast_tvadd(ast_tvnow(), whentohangup); 02192 } 02193 if (!ast_strlen_zero(dtmfcalled)) { 02194 ast_verb(3, "Sending DTMF '%s' to the called party.\n", dtmfcalled); 02195 res = ast_dtmf_stream(peer, chan, dtmfcalled, 250, 0); 02196 } 02197 if (!ast_strlen_zero(dtmfcalling)) { 02198 ast_verb(3, "Sending DTMF '%s' to the calling party.\n", dtmfcalling); 02199 res = ast_dtmf_stream(chan, peer, dtmfcalling, 250, 0); 02200 } 02201 } 02202 02203 if (res) { /* some error */ 02204 res = -1; 02205 } else { 02206 if (ast_test_flag64(peerflags, OPT_CALLEE_TRANSFER)) 02207 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 02208 if (ast_test_flag64(peerflags, OPT_CALLER_TRANSFER)) 02209 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 02210 if (ast_test_flag64(peerflags, OPT_CALLEE_HANGUP)) 02211 ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT); 02212 if (ast_test_flag64(peerflags, OPT_CALLER_HANGUP)) 02213 ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT); 02214 if (ast_test_flag64(peerflags, OPT_CALLEE_MONITOR)) 02215 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON); 02216 if (ast_test_flag64(peerflags, OPT_CALLER_MONITOR)) 02217 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON); 02218 if (ast_test_flag64(peerflags, OPT_CALLEE_PARK)) 02219 ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL); 02220 if (ast_test_flag64(peerflags, OPT_CALLER_PARK)) 02221 ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL); 02222 if (ast_test_flag64(peerflags, OPT_CALLEE_MIXMONITOR)) 02223 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMIXMON); 02224 if (ast_test_flag64(peerflags, OPT_CALLER_MIXMONITOR)) 02225 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMIXMON); 02226 if (ast_test_flag64(peerflags, OPT_GO_ON)) 02227 ast_set_flag(&(config.features_caller), AST_FEATURE_NO_H_EXTEN); 02228 02229 config.end_bridge_callback = end_bridge_callback; 02230 config.end_bridge_callback_data = chan; 02231 config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup; 02232 02233 if (moh) { 02234 moh = 0; 02235 ast_moh_stop(chan); 02236 } else if (sentringing) { 02237 sentringing = 0; 02238 ast_indicate(chan, -1); 02239 } 02240 /* Be sure no generators are left on it */ 02241 ast_deactivate_generator(chan); 02242 /* Make sure channels are compatible */ 02243 res = ast_channel_make_compatible(chan, peer); 02244 if (res < 0) { 02245 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", chan->name, peer->name); 02246 ast_hangup(peer); 02247 res = -1; 02248 goto done; 02249 } 02250 if (opermode) { 02251 struct oprmode oprmode; 02252 02253 oprmode.peer = peer; 02254 oprmode.mode = opermode; 02255 02256 ast_channel_setoption(chan, AST_OPTION_OPRMODE, &oprmode, sizeof(oprmode), 0); 02257 } 02258 res = ast_bridge_call(chan, peer, &config); 02259 } 02260 02261 strcpy(peer->context, chan->context); 02262 02263 if (ast_test_flag64(&opts, OPT_PEER_H) && ast_exists_extension(peer, peer->context, "h", 1, peer->cid.cid_num)) { 02264 int autoloopflag; 02265 int found; 02266 int res9; 02267 02268 strcpy(peer->exten, "h"); 02269 peer->priority = 1; 02270 autoloopflag = ast_test_flag(peer, AST_FLAG_IN_AUTOLOOP); /* save value to restore at the end */ 02271 ast_set_flag(peer, AST_FLAG_IN_AUTOLOOP); 02272 02273 while ((res9 = ast_spawn_extension(peer, peer->context, peer->exten, peer->priority, peer->cid.cid_num, &found, 1)) == 0) 02274 peer->priority++; 02275 02276 if (found && res9) { 02277 /* Something bad happened, or a hangup has been requested. */ 02278 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", peer->context, peer->exten, peer->priority, peer->name); 02279 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", peer->context, peer->exten, peer->priority, peer->name); 02280 } 02281 ast_set2_flag(peer, autoloopflag, AST_FLAG_IN_AUTOLOOP); /* set it back the way it was */ 02282 } 02283 if (!ast_check_hangup(peer) && ast_test_flag64(&opts, OPT_CALLEE_GO_ON) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GO_ON])) { 02284 replace_macro_delimiter(opt_args[OPT_ARG_CALLEE_GO_ON]); 02285 ast_parseable_goto(peer, opt_args[OPT_ARG_CALLEE_GO_ON]); 02286 ast_pbx_start(peer); 02287 } else { 02288 if (!ast_check_hangup(chan)) 02289 chan->hangupcause = peer->hangupcause; 02290 ast_hangup(peer); 02291 } 02292 } 02293 out: 02294 if (moh) { 02295 moh = 0; 02296 ast_moh_stop(chan); 02297 } else if (sentringing) { 02298 sentringing = 0; 02299 ast_indicate(chan, -1); 02300 } 02301 02302 if (delprivintro && ast_fileexists(pa.privintro, NULL, NULL) > 0) { 02303 ast_filedelete(pa.privintro, NULL); 02304 if (ast_fileexists(pa.privintro, NULL, NULL) > 0) { 02305 ast_log(LOG_NOTICE, "privacy: ast_filedelete didn't do its job on %s\n", pa.privintro); 02306 } else { 02307 ast_verb(3, "Successfully deleted %s intro file\n", pa.privintro); 02308 } 02309 } 02310 02311 ast_channel_early_bridge(chan, NULL); 02312 hanguptree(outgoing, NULL, 0); /* In this case, there's no answer anywhere */ 02313 pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status); 02314 senddialendevent(chan, pa.status); 02315 ast_debug(1, "Exiting with DIALSTATUS=%s.\n", pa.status); 02316 02317 if ((ast_test_flag64(peerflags, OPT_GO_ON)) && !ast_check_hangup(chan) && (res != AST_PBX_INCOMPLETE)) { 02318 if (!ast_tvzero(calldurationlimit)) 02319 memset(&chan->whentohangup, 0, sizeof(chan->whentohangup)); 02320 res = 0; 02321 } 02322 02323 done: 02324 if (config.warning_sound) { 02325 ast_free((char *)config.warning_sound); 02326 } 02327 if (config.end_sound) { 02328 ast_free((char *)config.end_sound); 02329 } 02330 if (config.start_sound) { 02331 ast_free((char *)config.start_sound); 02332 } 02333 return res; 02334 }
| static void do_forward | ( | struct chanlist * | o, | |
| struct cause_args * | num, | |||
| struct ast_flags64 * | peerflags, | |||
| int | single | |||
| ) | [static] |
helper function for wait_for_answer()
XXX this code is highly suspicious, as it essentially overwrites the outgoing channel without properly deleting it.
Definition at line 712 of file app_dial.c.
References ast_channel::accountcode, accountcode, ast_call(), AST_CAUSE_BUSY, ast_channel_datastore_inherit(), ast_channel_inherit_variables(), ast_channel_lock, ast_channel_make_compatible(), ast_channel_unlock, ast_clear_flag64, ast_copy_string(), ast_hangup(), ast_indicate(), ast_log(), AST_MAX_EXTENSION, ast_request(), ast_rtp_make_compatible(), ast_set_callerid(), ast_strdup, ast_string_field_set, ast_strlen_zero(), ast_test_flag64, ast_verb, ast_channel::call_forward, CAN_EARLY_BRIDGE, cause, ast_channel::cdrflags, cause_args::chan, chanlist::chan, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_name, ast_callerid::cid_num, ast_callerid::cid_rdnis, ast_channel::context, DIAL_STILLGOING, ast_channel::exten, get_cid_name(), handle_cause(), LOG_NOTICE, ast_channel::macroexten, ast_channel::name, ast_channel::nativeformats, cause_args::nochan, OPT_FORCECLID, OPT_IGNORE_FORWARDING, OPT_ORIGINAL_CLID, pbx_builtin_getvar_helper(), S_OR, S_REPLACE, senddialevent(), and ast_channel::tech.
Referenced by wait_for_answer().
00714 { 00715 char tmpchan[256]; 00716 struct ast_channel *original = o->chan; 00717 struct ast_channel *c = o->chan; /* the winner */ 00718 struct ast_channel *in = num->chan; /* the input channel */ 00719 char *stuff; 00720 char *tech; 00721 int cause; 00722 00723 ast_copy_string(tmpchan, c->call_forward, sizeof(tmpchan)); 00724 if ((stuff = strchr(tmpchan, '/'))) { 00725 *stuff++ = '\0'; 00726 tech = tmpchan; 00727 } else { 00728 const char *forward_context; 00729 ast_channel_lock(c); 00730 forward_context = pbx_builtin_getvar_helper(c, "FORWARD_CONTEXT"); 00731 if (ast_strlen_zero(forward_context)) { 00732 forward_context = NULL; 00733 } 00734 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", c->call_forward, forward_context ? forward_context : c->context); 00735 ast_channel_unlock(c); 00736 stuff = tmpchan; 00737 tech = "Local"; 00738 } 00739 /* Before processing channel, go ahead and check for forwarding */ 00740 ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, c->name); 00741 /* If we have been told to ignore forwards, just set this channel to null and continue processing extensions normally */ 00742 if (ast_test_flag64(peerflags, OPT_IGNORE_FORWARDING)) { 00743 ast_verb(3, "Forwarding %s to '%s/%s' prevented.\n", in->name, tech, stuff); 00744 c = o->chan = NULL; 00745 cause = AST_CAUSE_BUSY; 00746 } else { 00747 /* Setup parameters */ 00748 c = o->chan = ast_request(tech, in->nativeformats, stuff, &cause); 00749 if (c) { 00750 if (single) 00751 ast_channel_make_compatible(o->chan, in); 00752 ast_channel_inherit_variables(in, o->chan); 00753 ast_channel_datastore_inherit(in, o->chan); 00754 } else 00755 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause); 00756 } 00757 if (!c) { 00758 ast_clear_flag64(o, DIAL_STILLGOING); 00759 handle_cause(cause, num); 00760 ast_hangup(original); 00761 } else { 00762 char *new_cid_num, *new_cid_name; 00763 struct ast_channel *src; 00764 00765 if (CAN_EARLY_BRIDGE(peerflags, c, in)) { 00766 ast_rtp_make_compatible(c, in, single); 00767 } 00768 if (ast_test_flag64(o, OPT_FORCECLID)) { 00769 new_cid_num = ast_strdup(S_OR(in->macroexten, in->exten)); 00770 new_cid_name = NULL; /* XXX no name ? */ 00771 src = c; /* XXX possible bug in previous code, which used 'winner' ? it may have changed */ 00772 } else { 00773 new_cid_num = ast_strdup(in->cid.cid_num); 00774 new_cid_name = ast_strdup(in->cid.cid_name); 00775 src = in; 00776 } 00777 ast_string_field_set(c, accountcode, src->accountcode); 00778 c->cdrflags = src->cdrflags; 00779 S_REPLACE(c->cid.cid_num, new_cid_num); 00780 S_REPLACE(c->cid.cid_name, new_cid_name); 00781 00782 if (in->cid.cid_ani) { /* XXX or maybe unconditional ? */ 00783 S_REPLACE(c->cid.cid_ani, ast_strdup(in->cid.cid_ani)); 00784 } 00785 S_REPLACE(c->cid.cid_rdnis, ast_strdup(S_OR(in->macroexten, in->exten))); 00786 if (ast_call(c, tmpchan, 0)) { 00787 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan); 00788 ast_clear_flag64(o, DIAL_STILLGOING); 00789 ast_hangup(original); 00790 ast_hangup(c); 00791 c = o->chan = NULL; 00792 num->nochan++; 00793 } else { 00794 senddialevent(in, c, stuff); 00795 /* After calling, set callerid to extension */ 00796 if (!ast_test_flag64(peerflags, OPT_ORIGINAL_CLID)) { 00797 char cidname[AST_MAX_EXTENSION] = ""; 00798 ast_set_callerid(c, S_OR(in->macroexten, in->exten), get_cid_name(cidname, sizeof(cidname), in), NULL); 00799 } 00800 /* Hangup the original channel now, in case we needed it */ 00801 ast_hangup(original); 00802 } 00803 if (single) { 00804 ast_indicate(in, -1); 00805 } 00806 } 00807 }
| static int do_timelimit | ( | struct ast_channel * | chan, | |
| struct ast_bridge_config * | config, | |||
| char * | parse, | |||
| struct timeval * | calldurationlimit | |||
| ) | [static] |
Definition at line 1143 of file app_dial.c.
References ast_channel_lock, ast_channel_unlock, AST_FEATURE_PLAY_WARNING, ast_log(), ast_set_flag, ast_strdup, 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, ast_bridge_config::timelimit, var, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.
Referenced by dial_exec_full().
01145 { 01146 char *stringp = ast_strdupa(parse); 01147 char *limit_str, *warning_str, *warnfreq_str; 01148 const char *var; 01149 int play_to_caller = 0, play_to_callee = 0; 01150 int delta; 01151 01152 limit_str = strsep(&stringp, ":"); 01153 warning_str = strsep(&stringp, ":"); 01154 warnfreq_str = strsep(&stringp, ":"); 01155 01156 config->timelimit = atol(limit_str); 01157 if (warning_str) 01158 config->play_warning = atol(warning_str); 01159 if (warnfreq_str) 01160 config->warning_freq = atol(warnfreq_str); 01161 01162 if (!config->timelimit) { 01163 ast_log(LOG_WARNING, "Dial does not accept L(%s), hanging up.\n", limit_str); 01164 config->timelimit = config->play_warning = config->warning_freq = 0; 01165 config->warning_sound = NULL; 01166 return -1; /* error */ 01167 } else if ( (delta = config->play_warning - config->timelimit) > 0) { 01168 int w = config->warning_freq; 01169 01170 /* If the first warning is requested _after_ the entire call would end, 01171 and no warning frequency is requested, then turn off the warning. If 01172 a warning frequency is requested, reduce the 'first warning' time by 01173 that frequency until it falls within the call's total time limit. 01174 Graphically: 01175 timelim->| delta |<-playwarning 01176 0__________________|_________________| 01177 | w | | | | 01178 01179 so the number of intervals to cut is 1+(delta-1)/w 01180 */ 01181 01182 if (w == 0) { 01183 config->play_warning = 0; 01184 } else { 01185 config->play_warning -= w * ( 1 + (delta-1)/w ); 01186 if (config->play_warning < 1) 01187 config->play_warning = config->warning_freq = 0; 01188 } 01189 } 01190 01191 ast_channel_lock(chan); 01192 01193 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER"); 01194 01195 play_to_caller = var ? ast_true(var) : 1; 01196 01197 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE"); 01198 play_to_callee = var ? ast_true(var) : 0; 01199 01200 if (!play_to_caller && !play_to_callee) 01201 play_to_caller = 1; 01202 01203 var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE"); 01204 config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft"); 01205 01206 /* The code looking at config wants a NULL, not just "", to decide 01207 * that the message should not be played, so we replace "" with NULL. 01208 * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is 01209 * not found. 01210 */ 01211 01212 var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE"); 01213 config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 01214 01215 var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE"); 01216 config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 01217 01218 ast_channel_unlock(chan); 01219 01220 /* undo effect of S(x) in case they are both used */ 01221 calldurationlimit->tv_sec = 0; 01222 calldurationlimit->tv_usec = 0; 01223 01224 /* more efficient to do it like S(x) does since no advanced opts */ 01225 if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) { 01226 calldurationlimit->tv_sec = config->timelimit / 1000; 01227 calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000; 01228 ast_verb(3, "Setting call duration limit to %.3lf seconds.\n", 01229 calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0); 01230 config->timelimit = play_to_caller = play_to_callee = 01231 config->play_warning = config->warning_freq = 0; 01232 } else { 01233 ast_verb(3, "Limit Data for this call:\n"); 01234 ast_verb(4, "timelimit = %ld\n", config->timelimit); 01235 ast_verb(4, "play_warning = %ld\n", config->play_warning); 01236 ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no"); 01237 ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no"); 01238 ast_verb(4, "warning_freq = %ld\n", config->warning_freq); 01239 ast_verb(4, "start_sound = %s\n", S_OR(config->start_sound, "")); 01240 ast_verb(4, "warning_sound = %s\n", config->warning_sound); 01241 ast_verb(4, "end_sound = %s\n", S_OR(config->end_sound, "")); 01242 } 01243 if (play_to_caller) 01244 ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 01245 if (play_to_callee) 01246 ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 01247 return 0; 01248 }
| static void end_bridge_callback | ( | void * | data | ) | [static] |
Definition at line 1486 of file app_dial.c.
References ast_cdr::answer, ast_channel_lock, ast_channel_unlock, buf, ast_channel::cdr, pbx_builtin_setvar_helper(), and ast_cdr::start.
Referenced by dial_exec_full().
01487 { 01488 char buf[80]; 01489 time_t end; 01490 struct ast_channel *chan = data; 01491 01492 if (!chan->cdr) { 01493 return; 01494 } 01495 01496 time(&end); 01497 01498 ast_channel_lock(chan); 01499 if (chan->cdr->answer.tv_sec) { 01500 snprintf(buf, sizeof(buf), "%ld", end - chan->cdr->answer.tv_sec); 01501 pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf); 01502 } 01503 01504 if (chan->cdr->start.tv_sec) { 01505 snprintf(buf, sizeof(buf), "%ld", end - chan->cdr->start.tv_sec); 01506 pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf); 01507 } 01508 ast_channel_unlock(chan); 01509 }
| static void end_bridge_callback_data_fixup | ( | struct ast_bridge_config * | bconfig, | |
| struct ast_channel * | originator, | |||
| struct ast_channel * | terminator | |||
| ) | [static] |
Definition at line 1511 of file app_dial.c.
References ast_bridge_config::end_bridge_callback_data.
Referenced by dial_exec_full().
01511 { 01512 bconfig->end_bridge_callback_data = originator; 01513 }
| static const char* get_cid_name | ( | char * | name, | |
| int | namelen, | |||
| struct ast_channel * | chan | |||
| ) | [static] |
Definition at line 672 of file app_dial.c.
References ast_get_hint(), ast_channel::context, context, ast_channel::exten, exten, ast_channel::macrocontext, ast_channel::macroexten, and S_OR.
Referenced by dial_exec_full(), and do_forward().
00673 { 00674 const char *context = S_OR(chan->macrocontext, chan->context); 00675 const char *exten = S_OR(chan->macroexten, chan->exten); 00676 00677 return ast_get_hint(NULL, 0, name, namelen, chan, context, exten) ? name : ""; 00678 }
| static void handle_cause | ( | int | cause, | |
| struct cause_args * | num | |||
| ) | [static] |
Definition at line 607 of file app_dial.c.
References AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, AST_CAUSE_NO_ANSWER, AST_CAUSE_NO_ROUTE_DESTINATION, AST_CAUSE_NORMAL_CLEARING, AST_CAUSE_UNREGISTERED, ast_cdr_busy(), ast_cdr_failed(), ast_cdr_noanswer(), cause_args::busy, ast_channel::cdr, cause_args::chan, cause_args::congestion, and cause_args::nochan.
Referenced by dial_exec_full(), do_forward(), and wait_for_answer().
00608 { 00609 struct ast_cdr *cdr = num->chan->cdr; 00610 00611 switch(cause) { 00612 case AST_CAUSE_BUSY: 00613 if (cdr) 00614 ast_cdr_busy(cdr); 00615 num->busy++; 00616 break; 00617 00618 case AST_CAUSE_CONGESTION: 00619 if (cdr) 00620 ast_cdr_failed(cdr); 00621 num->congestion++; 00622 break; 00623 00624 case AST_CAUSE_NO_ROUTE_DESTINATION: 00625 case AST_CAUSE_UNREGISTERED: 00626 if (cdr) 00627 ast_cdr_failed(cdr); 00628 num->nochan++; 00629 break; 00630 00631 case AST_CAUSE_NO_ANSWER: 00632 if (cdr) { 00633 ast_cdr_noanswer(cdr); 00634 } 00635 break; 00636 case AST_CAUSE_NORMAL_CLEARING: 00637 break; 00638 00639 default: 00640 num->nochan++; 00641 break; 00642 } 00643 }
| static void hanguptree | ( | struct chanlist * | outgoing, | |
| struct ast_channel * | exception, | |||
| int | answered_elsewhere | |||
| ) | [static] |
Definition at line 574 of file app_dial.c.
References AST_CAUSE_ANSWERED_ELSEWHERE, AST_FLAG_ANSWERED_ELSEWHERE, ast_free, ast_hangup(), ast_set_flag, chanlist::chan, ast_channel::hangupcause, and chanlist::next.
Referenced by dial_exec_full().
00575 { 00576 /* Hang up a tree of stuff */ 00577 struct chanlist *oo; 00578 while (outgoing) { 00579 /* Hangup any existing lines we have open */ 00580 if (outgoing->chan && (outgoing->chan != exception)) { 00581 if (answered_elsewhere) { 00582 /* The flag is used for local channel inheritance and stuff */ 00583 ast_set_flag(outgoing->chan, AST_FLAG_ANSWERED_ELSEWHERE); 00584 /* This is for the channel drivers */ 00585 outgoing->chan->hangupcause = AST_CAUSE_ANSWERED_ELSEWHERE; 00586 } 00587 ast_hangup(outgoing->chan); 00588 } 00589 oo = outgoing; 00590 outgoing = outgoing->next; 00591 ast_free(oo); 00592 } 00593 }
| static int load_module | ( | void | ) | [static] |
Definition at line 2469 of file app_dial.c.
References ast_add_extension2(), ast_context_find_or_create(), ast_free_ptr(), ast_log(), ast_register_application_xml, ast_strdup, dial_exec(), LOG_ERROR, and retrydial_exec().
02470 { 02471 int res; 02472 struct ast_context *con; 02473 02474 con = ast_context_find_or_create(NULL, NULL, "app_dial_gosub_virtual_context", "app_dial"); 02475 if (!con) 02476 ast_log(LOG_ERROR, "Dial virtual context 'app_dial_gosub_virtual_context' does not exist and unable to create\n"); 02477 else 02478 ast_add_extension2(con, 1, "s", 1, NULL, NULL, "NoOp", ast_strdup(""), ast_free_ptr, "app_dial"); 02479 02480 res = ast_register_application_xml(app, dial_exec); 02481 res |= ast_register_application_xml(rapp, retrydial_exec); 02482 02483 return res; 02484 }
| static int onedigit_goto | ( | struct ast_channel * | chan, | |
| const char * | context, | |||
| char | exten, | |||
| int | pri | |||
| ) | [static] |
Definition at line 653 of file app_dial.c.
References ast_goto_if_exists(), ast_strlen_zero(), ast_channel::context, and ast_channel::macrocontext.
Referenced by retrydial_exec(), and wait_for_answer().
00654 { 00655 char rexten[2] = { exten, '\0' }; 00656 00657 if (context) { 00658 if (!ast_goto_if_exists(chan, context, rexten, pri)) 00659 return 1; 00660 } else { 00661 if (!ast_goto_if_exists(chan, chan->context, rexten, pri)) 00662 return 1; 00663 else if (!ast_strlen_zero(chan->macrocontext)) { 00664 if (!ast_goto_if_exists(chan, chan->macrocontext, rexten, pri)) 00665 return 1; 00666 } 00667 } 00668 return 0; 00669 }
| static void replace_macro_delimiter | ( | char * | s | ) | [static] |
Definition at line 1124 of file app_dial.c.
Referenced by dial_exec_full().
| static int retrydial_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 2345 of file app_dial.c.
References AST_APP_ARG, ast_channel_lock, ast_channel_unlock, AST_DECLARE_APP_ARGS, AST_DIGIT_ANY, ast_fileexists(), AST_FLAG_MOH, ast_log(), ast_moh_start(), ast_moh_stop(), AST_PBX_INCOMPLETE, AST_STANDARD_APP_ARGS, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_test_flag64, ast_waitfordigit(), ast_waitstream(), context, ast_channel::data, dial_exec_full(), ast_channel::language, LOG_ERROR, LOG_WARNING, onedigit_goto(), OPT_DTMF_EXIT, parse(), and pbx_builtin_getvar_helper().
Referenced by load_module().
02346 { 02347 char *parse; 02348 const char *context = NULL; 02349 int sleepms = 0, loops = 0, res = -1; 02350 struct ast_flags64 peerflags = { 0, }; 02351 AST_DECLARE_APP_ARGS(args, 02352 AST_APP_ARG(announce); 02353 AST_APP_ARG(sleep); 02354 AST_APP_ARG(retries); 02355 AST_APP_ARG(dialdata); 02356 ); 02357 02358 if (ast_strlen_zero(data)) { 02359 ast_log(LOG_WARNING, "RetryDial requires an argument!\n"); 02360 return -1; 02361 } 02362 02363 parse = ast_strdupa(data); 02364 AST_STANDARD_APP_ARGS(args, parse); 02365 02366 if (!ast_strlen_zero(args.sleep) && (sleepms = atoi(args.sleep))) 02367 sleepms *= 1000; 02368 02369 if (!ast_strlen_zero(args.retries)) { 02370 loops = atoi(args.retries); 02371 } 02372 02373 if (!args.dialdata) { 02374 ast_log(LOG_ERROR, "%s requires a 4th argument (dialdata)\n", rapp); 02375 goto done; 02376 } 02377 02378 if (sleepms < 1000) 02379 sleepms = 10000; 02380 02381 if (!loops) 02382 loops = -1; /* run forever */ 02383 02384 ast_channel_lock(chan); 02385 context = pbx_builtin_getvar_helper(chan, "EXITCONTEXT"); 02386 context = !ast_strlen_zero(context) ? ast_strdupa(context) : NULL; 02387 ast_channel_unlock(chan); 02388 02389 res = 0; 02390 while (loops) { 02391 int continue_exec; 02392 02393 chan->data = "Retrying"; 02394 if (ast_test_flag(chan, AST_FLAG_MOH)) 02395 ast_moh_stop(chan); 02396 02397 res = dial_exec_full(chan, args.dialdata, &peerflags, &continue_exec); 02398 if (continue_exec) 02399 break; 02400 02401 if (res == 0) { 02402 if (ast_test_flag64(&peerflags, OPT_DTMF_EXIT)) { 02403 if (!ast_strlen_zero(args.announce)) { 02404 if (ast_fileexists(args.announce, NULL, chan->language) > 0) { 02405 if (!(res = ast_streamfile(chan, args.announce, chan->language))) 02406 ast_waitstream(chan, AST_DIGIT_ANY); 02407 } else 02408 ast_log(LOG_WARNING, "Announce file \"%s\" specified in Retrydial does not exist\n", args.announce); 02409 } 02410 if (!res && sleepms) { 02411 if (!ast_test_flag(chan, AST_FLAG_MOH)) 02412 ast_moh_start(chan, NULL, NULL); 02413 res = ast_waitfordigit(chan, sleepms); 02414 } 02415 } else { 02416 if (!ast_strlen_zero(args.announce)) { 02417 if (ast_fileexists(args.announce, NULL, chan->language) > 0) { 02418 if (!(res = ast_streamfile(chan, args.announce, chan->language))) 02419 res = ast_waitstream(chan, ""); 02420 } else 02421 ast_log(LOG_WARNING, "Announce file \"%s\" specified in Retrydial does not exist\n", args.announce); 02422 } 02423 if (sleepms) { 02424 if (!ast_test_flag(chan, AST_FLAG_MOH)) 02425 ast_moh_start(chan, NULL, NULL); 02426 if (!res) 02427 res = ast_waitfordigit(chan, sleepms); 02428 } 02429 } 02430 } 02431 02432 if (res < 0 || res == AST_PBX_INCOMPLETE) { 02433 break; 02434 } else if (res > 0) { /* Trying to send the call elsewhere (1 digit ext) */ 02435 if (onedigit_goto(chan, context, (char) res, 1)) { 02436 res = 0; 02437 break; 02438 } 02439 } 02440 loops--; 02441 } 02442 if (loops == 0) 02443 res = 0; 02444 else if (res == 1) 02445 res = 0; 02446 02447 if (ast_test_flag(chan, AST_FLAG_MOH)) 02448 ast_moh_stop(chan); 02449 done: 02450 return res; 02451 }
| static void senddialendevent | ( | const struct ast_channel * | src, | |
| const char * | dialstatus | |||
| ) | [static] |
Definition at line 696 of file app_dial.c.
References EVENT_FLAG_CALL, manager_event, ast_channel::name, and ast_channel::uniqueid.
Referenced by dial_exec_full().
00697 { 00698 manager_event(EVENT_FLAG_CALL, "Dial", 00699 "SubEvent: End\r\n" 00700 "Channel: %s\r\n" 00701 "UniqueID: %s\r\n" 00702 "DialStatus: %s\r\n", 00703 src->name, src->uniqueid, dialstatus); 00704 }
| static void senddialevent | ( | struct ast_channel * | src, | |
| struct ast_channel * | dst, | |||
| const char * | dialstring | |||
| ) | [static] |
Definition at line 680 of file app_dial.c.
References ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, EVENT_FLAG_CALL, manager_event, ast_channel::name, S_OR, and ast_channel::uniqueid.
Referenced by dial_exec_full(), and do_forward().
00681 { 00682 manager_event(EVENT_FLAG_CALL, "Dial", 00683 "SubEvent: Begin\r\n" 00684 "Channel: %s\r\n" 00685 "Destination: %s\r\n" 00686 "CallerIDNum: %s\r\n" 00687 "CallerIDName: %s\r\n" 00688 "UniqueID: %s\r\n" 00689 "DestUniqueID: %s\r\n" 00690 "Dialstring: %s\r\n", 00691 src->name, dst->name, S_OR(src->cid.cid_num, "<unknown>"), 00692 S_OR(src->cid.cid_name, "<unknown>"), src->uniqueid, 00693 dst->uniqueid, dialstring ? dialstring : ""); 00694 }
| static int setup_privacy_args | ( | struct privacy_args * | pa, | |
| struct ast_flags64 * | opts, | |||
| char * | opt_args[], | |||
| struct ast_channel * | chan | |||
| ) | [static] |
returns 1 if successful, 0 or <0 if the caller should 'goto out'
Definition at line 1385 of file app_dial.c.
References ast_answer(), ast_config_AST_DATA_DIR, ast_copy_string(), ast_dsp_get_threshold_from_settings(), ast_filedelete(), ast_fileexists(), ast_log(), ast_mkdir(), ast_play_and_record(), AST_PRIVACY_ALLOW, ast_privacy_check(), AST_PRIVACY_DENY, AST_PRIVACY_KILL, AST_PRIVACY_TORTURE, AST_PRIVACY_UNKNOWN, ast_shrink_phone_number(), ast_streamfile(), ast_strlen_zero(), ast_test_flag64, ast_verb, ast_waitstream(), ast_channel::cid, ast_callerid::cid_num, ast_channel::exten, ast_channel::language, LOG_NOTICE, LOG_WARNING, ast_channel::name, OPT_ARG_PRIVACY, OPT_PRIVACY, OPT_SCREEN_NOCLID, privacy_args::privcid, privacy_args::privdb_val, privacy_args::privintro, silencethreshold, privacy_args::status, and THRESHOLD_SILENCE.
Referenced by dial_exec_full().
01387 { 01388 char callerid[60]; 01389 int res; 01390 char *l; 01391 int silencethreshold; 01392 01393 if (!ast_strlen_zero(chan->cid.cid_num)) { 01394 l = ast_strdupa(chan->cid.cid_num); 01395 ast_shrink_phone_number(l); 01396 if (ast_test_flag64(opts, OPT_PRIVACY) ) { 01397 ast_verb(3, "Privacy DB is '%s', clid is '%s'\n", opt_args[OPT_ARG_PRIVACY], l); 01398 pa->privdb_val = ast_privacy_check(opt_args[OPT_ARG_PRIVACY], l); 01399 } else { 01400 ast_verb(3, "Privacy Screening, clid is '%s'\n", l); 01401 pa->privdb_val = AST_PRIVACY_UNKNOWN; 01402 } 01403 } else { 01404 char *tnam, *tn2; 01405 01406 tnam = ast_strdupa(chan->name); 01407 /* clean the channel name so slashes don't try to end up in disk file name */ 01408 for (tn2 = tnam; *tn2; tn2++) { 01409 if (*tn2 == '/') /* any other chars to be afraid of? */ 01410 *tn2 = '='; 01411 } 01412 ast_verb(3, "Privacy-- callerid is empty\n"); 01413 01414 snprintf(callerid, sizeof(callerid), "NOCALLERID_%s%s", chan->exten, tnam); 01415 l = callerid; 01416 pa->privdb_val = AST_PRIVACY_UNKNOWN; 01417 } 01418 01419 ast_copy_string(pa->privcid, l, sizeof(pa->privcid)); 01420 01421 if (strncmp(pa->privcid, "NOCALLERID", 10) != 0 && ast_test_flag64(opts, OPT_SCREEN_NOCLID)) { 01422 /* if callerid is set and OPT_SCREEN_NOCLID is set also */ 01423 ast_verb(3, "CallerID set (%s); N option set; Screening should be off\n", pa->privcid); 01424 pa->privdb_val = AST_PRIVACY_ALLOW; 01425 } else if (ast_test_flag64(opts, OPT_SCREEN_NOCLID) && strncmp(pa->privcid, "NOCALLERID", 10) == 0) { 01426 ast_verb(3, "CallerID blank; N option set; Screening should happen; dbval is %d\n", pa->privdb_val); 01427 } 01428 01429 if (pa->privdb_val == AST_PRIVACY_DENY) { 01430 ast_verb(3, "Privacy DB reports PRIVACY_DENY for this callerid. Dial reports unavailable\n"); 01431 ast_copy_string(pa->status, "NOANSWER", sizeof(pa->status)); 01432 return 0; 01433 } else if (pa->privdb_val == AST_PRIVACY_KILL) { 01434 ast_copy_string(pa->status, "DONTCALL", sizeof(pa->status)); 01435 return 0; /* Is this right? */ 01436 } else if (pa->privdb_val == AST_PRIVACY_TORTURE) { 01437 ast_copy_string(pa->status, "TORTURE", sizeof(pa->status)); 01438 return 0; /* is this right??? */ 01439 } else if (pa->privdb_val == AST_PRIVACY_UNKNOWN) { 01440 /* Get the user's intro, store it in priv-callerintros/$CID, 01441 unless it is already there-- this should be done before the 01442 call is actually dialed */ 01443 01444 /* make sure the priv-callerintros dir actually exists */ 01445 snprintf(pa->privintro, sizeof(pa->privintro), "%s/sounds/priv-callerintros", ast_config_AST_DATA_DIR); 01446 if ((res = ast_mkdir(pa->privintro, 0755))) { 01447 ast_log(LOG_WARNING, "privacy: can't create directory priv-callerintros: %s\n", strerror(res)); 01448 return -1; 01449 } 01450 01451 snprintf(pa->privintro, sizeof(pa->privintro), "priv-callerintros/%s", pa->privcid); 01452 if (ast_fileexists(pa->privintro, NULL, NULL ) > 0 && strncmp(pa->privcid, "NOCALLERID", 10) != 0) { 01453 /* the DELUX version of this code would allow this caller the 01454 option to hear and retape their previously recorded intro. 01455 */ 01456 } else { 01457 int duration; /* for feedback from play_and_wait */ 01458 /* the file doesn't exist yet. Let the caller submit his 01459 vocal intro for posterity */ 01460 /* priv-recordintro script: 01461 01462 "At the tone, please say your name:" 01463 01464 */ 01465 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE); 01466 ast_answer(chan); 01467 res = ast_play_and_record(chan, "priv-recordintro", pa->privintro, 4, "gsm", &duration, silencethreshold, 2000, 0); /* NOTE: I've reduced the total time to 4 sec */ 01468 /* don't think we'll need a lock removed, we took care of 01469 conflicts by naming the pa.privintro file */ 01470 if (res == -1) { 01471 /* Delete the file regardless since they hung up during recording */ 01472 ast_filedelete(pa->privintro, NULL); 01473 if (ast_fileexists(pa->privintro, NULL, NULL) > 0) 01474 ast_log(LOG_NOTICE, "privacy: ast_filedelete didn't do its job on %s\n", pa->privintro); 01475 else 01476 ast_verb(3, "Successfully deleted %s intro file\n", pa->privintro); 01477 return -1; 01478 } 01479 if (!ast_streamfile(chan, "vm-dialout", chan->language) ) 01480 ast_waitstream(chan, ""); 01481 } 01482 } 01483 return 1; /* success */ 01484 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 2453 of file app_dial.c.
References ast_context_destroy(), ast_context_find(), ast_context_remove_extension2(), and ast_unregister_application().
02454 { 02455 int res; 02456 struct ast_context *con; 02457 02458 res = ast_unregister_application(app); 02459 res |= ast_unregister_application(rapp); 02460 02461 if ((con = ast_context_find("app_dial_gosub_virtual_context"))) { 02462 ast_context_remove_extension2(con, "s", 1, NULL, 0); 02463 ast_context_destroy(con, "app_dial"); /* leave nothing behind */ 02464 } 02465 02466 return res; 02467 }
| static int valid_priv_reply | ( | struct ast_flags64 * | opts, | |
| int | res | |||
| ) | [static] |
Definition at line 1132 of file app_dial.c.
References ast_test_flag64, OPT_PRIVACY, and OPT_SCREENING.
01133 { 01134 if (res < '1') 01135 return 0; 01136 if (ast_test_flag64(opts, OPT_PRIVACY) && res <= '5') 01137 return 1; 01138 if (ast_test_flag64(opts, OPT_SCREENING) && res <= '4') 01139 return 1; 01140 return 0; 01141 }
| static struct ast_channel* wait_for_answer | ( | struct ast_channel * | in, | |
| struct chanlist * | outgoing, | |||
| int * | to, | |||
| struct ast_flags64 * | peerflags, | |||
| struct privacy_args * | pa, | |||
| const struct cause_args * | num_in, | |||
| int * | result | |||
| ) | [static, read] |
Definition at line 818 of file app_dial.c.
References ast_channel::_state, ast_cdr::answer, AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, AST_CAUSE_NORMAL_CLEARING, AST_CDR_ANSWERED, ast_cdr_noanswer(), ast_channel_early_bridge(), ast_channel_lock, ast_channel_make_compatible(), ast_channel_sendhtml(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag64, AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OFFHOOK, AST_CONTROL_PROCEEDING, AST_CONTROL_PROGRESS, AST_CONTROL_RINGING, AST_CONTROL_SRCUPDATE, AST_CONTROL_UNHOLD, AST_CONTROL_VIDUPDATE, ast_copy_flags64, ast_copy_string(), ast_deactivate_generator(), ast_debug, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_HTML, AST_FRAME_IMAGE, AST_FRAME_TEXT, AST_FRAME_VOICE, ast_frfree, ast_hangup(), ast_indicate(), ast_indicate_data(), ast_log(), AST_MAX_WATCHERS, ast_poll_channel_add(), ast_poll_channel_del(), ast_read(), AST_STATE_UP, ast_string_field_set, ast_strlen_zero(), ast_test_flag64, ast_tvnow(), ast_verb, ast_waitfor_n(), ast_write(), cause_args::busy, ast_channel::call_forward, CAN_EARLY_BRIDGE, ast_channel::cdr, chanlist::chan, cause_args::congestion, context, ast_frame::data, ast_frame::datalen, DIAL_NOFORWARDHTML, DIAL_STILLGOING, dialcontext, ast_cdr::disposition, do_forward(), ast_channel::exten, f, ast_frame::frametype, handle_cause(), ast_channel::hangupcause, LOG_WARNING, ast_channel::name, chanlist::next, cause_args::nochan, onedigit_goto(), OPT_CALLEE_HANGUP, OPT_CALLEE_MIXMONITOR, OPT_CALLEE_MONITOR, OPT_CALLEE_PARK, OPT_CALLEE_TRANSFER, OPT_CALLER_HANGUP, OPT_CALLER_MIXMONITOR, OPT_CALLER_MONITOR, OPT_CALLER_PARK, OPT_CALLER_TRANSFER, OPT_DTMF_EXIT, OPT_MUSICBACK, OPT_RINGBACK, pbx_builtin_getvar_helper(), ast_frame::ptr, privacy_args::sentringing, privacy_args::status, ast_frame::subclass, and ast_frame::uint32.
Referenced by dial_exec_full().
00822 { 00823 struct cause_args num = *num_in; 00824 int prestart = num.busy + num.congestion + num.nochan; 00825 int orig = *to; 00826 struct ast_channel *peer = NULL; 00827 /* single is set if only one destination is enabled */ 00828 int single = outgoing && !outgoing->next && !ast_test_flag64(outgoing, OPT_MUSICBACK | OPT_RINGBACK); 00829 #ifdef HAVE_EPOLL 00830 struct chanlist *epollo; 00831 #endif 00832 00833 if (single) { 00834 /* Turn off hold music, etc */ 00835 ast_deactivate_generator(in); 00836 /* If we are calling a single channel, make them compatible for in-band tone purpose */ 00837 ast_channel_make_compatible(outgoing->chan, in); 00838 } 00839 00840 #ifdef HAVE_EPOLL 00841 for (epollo = outgoing; epollo; epollo = epollo->next) 00842 ast_poll_channel_add(in, epollo->chan); 00843 #endif 00844 00845 while (*to && !peer) { 00846 struct chanlist *o; 00847 int pos = 0; /* how many channels do we handle */ 00848 int numlines = prestart; 00849 struct ast_channel *winner; 00850 struct ast_channel *watchers[AST_MAX_WATCHERS]; 00851 00852 watchers[pos++] = in; 00853 for (o = outgoing; o; o = o->next) { 00854 /* Keep track of important channels */ 00855 if (ast_test_flag64(o, DIAL_STILLGOING) && o->chan) 00856 watchers[pos++] = o->chan; 00857 numlines++; 00858 } 00859 if (pos == 1) { /* only the input channel is available */ 00860 if (numlines == (num.busy + num.congestion + num.nochan)) { 00861 ast_verb(2, "Everyone is busy/congested at this time (%d:%d/%d/%d)\n", numlines, num.busy, num.congestion, num.nochan); 00862 if (num.busy) 00863 strcpy(pa->status, "BUSY"); 00864 else if (num.congestion) 00865 strcpy(pa->status, "CONGESTION"); 00866 else if (num.nochan) 00867 strcpy(pa->status, "CHANUNAVAIL"); 00868 } else { 00869 ast_verb(3, "No one is available to answer at this time (%d:%d/%d/%d)\n", numlines, num.busy, num.congestion, num.nochan); 00870 } 00871 *to = 0; 00872 return NULL; 00873 } 00874 winner = ast_waitfor_n(watchers, pos, to); 00875 for (o = outgoing; o; o = o->next) { 00876 struct ast_frame *f; 00877 struct ast_channel *c = o->chan; 00878 00879 if (c == NULL) 00880 continue; 00881 if (ast_test_flag64(o, DIAL_STILLGOING) && c->_state == AST_STATE_UP) { 00882 if (!peer) { 00883 ast_verb(3, "%s answered %s\n", c->name, in->name); 00884 peer = c; 00885 ast_copy_flags64(peerflags, o, 00886 OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER | 00887 OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP | 00888 OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR | 00889 OPT_CALLEE_PARK | OPT_CALLER_PARK | 00890 OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR | 00891 DIAL_NOFORWARDHTML); 00892 ast_string_field_set(c, dialcontext, ""); 00893 ast_copy_string(c->exten, "", sizeof(c->exten)); 00894 } 00895 continue; 00896 } 00897 if (c != winner) 00898 continue; 00899 /* here, o->chan == c == winner */ 00900 if (!ast_strlen_zero(c->call_forward)) { 00901 do_forward(o, &num, peerflags, single); 00902 continue; 00903 } 00904 f = ast_read(winner); 00905 if (!f) { 00906 in->hangupcause = c->hangupcause; 00907 #ifdef HAVE_EPOLL 00908 ast_poll_channel_del(in, c); 00909 #endif 00910 ast_hangup(c); 00911 c = o->chan = NULL; 00912 ast_clear_flag64(o, DIAL_STILLGOING); 00913 handle_cause(in->hangupcause, &num); 00914 continue; 00915 } 00916 if (f->frametype == AST_FRAME_CONTROL) { 00917 switch(f->subclass) { 00918 case AST_CONTROL_ANSWER: 00919 /* This is our guy if someone answered. */ 00920 if (!peer) { 00921 ast_verb(3, "%s answered %s\n", c->name, in->name); 00922 peer = c; 00923 if (peer->cdr) { 00924 peer->cdr->answer = ast_tvnow(); 00925 peer->cdr->disposition = AST_CDR_ANSWERED; 00926 } 00927 ast_copy_flags64(peerflags, o, 00928 OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER | 00929 OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP | 00930 OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR | 00931 OPT_CALLEE_PARK | OPT_CALLER_PARK | 00932 OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR | 00933 DIAL_NOFORWARDHTML); 00934 ast_string_field_set(c, dialcontext, ""); 00935 ast_copy_string(c->exten, "", sizeof(c->exten)); 00936 if (CAN_EARLY_BRIDGE(peerflags, in, peer)) 00937 /* Setup early bridge if appropriate */ 00938 ast_channel_early_bridge(in, peer); 00939 } 00940 /* If call has been answered, then the eventual hangup is likely to be normal hangup */ 00941 in->hangupcause = AST_CAUSE_NORMAL_CLEARING; 00942 c->hangupcause = AST_CAUSE_NORMAL_CLEARING; 00943 break; 00944 case AST_CONTROL_BUSY: 00945 ast_verb(3, "%s is busy\n", c->name); 00946 in->hangupcause = c->hangupcause; 00947 ast_hangup(c); 00948 c = o->chan = NULL; 00949 ast_clear_flag64(o, DIAL_STILLGOING); 00950 handle_cause(AST_CAUSE_BUSY, &num); 00951 break; 00952 case AST_CONTROL_CONGESTION: 00953 ast_verb(3, "%s is circuit-busy\n", c->name); 00954 in->hangupcause = c->hangupcause; 00955 ast_hangup(c); 00956 c = o->chan = NULL; 00957 ast_clear_flag64(o, DIAL_STILLGOING); 00958 handle_cause(AST_CAUSE_CONGESTION, &num); 00959 break; 00960 case AST_CONTROL_RINGING: 00961 ast_verb(3, "%s is ringing\n", c->name); 00962 /* Setup early media if appropriate */ 00963 if (single && CAN_EARLY_BRIDGE(peerflags, in, c)) 00964 ast_channel_early_bridge(in, c); 00965 if (!(pa->sentringing) && !ast_test_flag64(outgoing, OPT_MUSICBACK)) { 00966 ast_indicate(in, AST_CONTROL_RINGING); 00967 pa->sentringing++; 00968 } 00969 break; 00970 case AST_CONTROL_PROGRESS: 00971 ast_verb(3, "%s is making progress passing it to %s\n", c->name, in->name); 00972 /* Setup early media if appropriate */ 00973 if (single && CAN_EARLY_BRIDGE(peerflags, in, c)) 00974 ast_channel_early_bridge(in, c); 00975 if (!ast_test_flag64(outgoing, OPT_RINGBACK)) 00976 if (single || (!single && !pa->sentringing)) { 00977 ast_indicate(in, AST_CONTROL_PROGRESS); 00978 } 00979 break; 00980 case AST_CONTROL_VIDUPDATE: 00981 ast_verb(3, "%s requested a video update, passing it to %s\n", c->name, in->name); 00982 ast_indicate(in, AST_CONTROL_VIDUPDATE); 00983 break; 00984 case AST_CONTROL_SRCUPDATE: 00985 ast_verb(3, "%s requested a source update, passing it to %s\n", c->name, in->name); 00986 ast_indicate(in, AST_CONTROL_SRCUPDATE); 00987 break; 00988 case AST_CONTROL_PROCEEDING: 00989 ast_verb(3, "%s is proceeding passing it to %s\n", c->name, in->name); 00990 if (single && CAN_EARLY_BRIDGE(peerflags, in, c)) 00991 ast_channel_early_bridge(in, c); 00992 if (!ast_test_flag64(outgoing, OPT_RINGBACK)) 00993 ast_indicate(in, AST_CONTROL_PROCEEDING); 00994 break; 00995 case AST_CONTROL_HOLD: 00996 ast_verb(3, "Call on %s placed on hold\n", c->name); 00997 ast_indicate(in, AST_CONTROL_HOLD); 00998 break; 00999 case AST_CONTROL_UNHOLD: 01000 ast_verb(3, "Call on %s left from hold\n", c->name); 01001 ast_indicate(in, AST_CONTROL_UNHOLD); 01002 break; 01003 case AST_CONTROL_OFFHOOK: 01004 case AST_CONTROL_FLASH: 01005 /* Ignore going off hook and flash */ 01006 break; 01007 case -1: 01008 if (!ast_test_flag64(outgoing, OPT_RINGBACK | OPT_MUSICBACK)) { 01009 ast_verb(3, "%s stopped sounds\n", c->name); 01010 ast_indicate(in, -1); 01011 pa->sentringing = 0; 01012 } 01013 break; 01014 default: 01015 ast_debug(1, "Dunno what to do with control type %d\n", f->subclass); 01016 } 01017 } else if (single) { 01018 switch (f->frametype) { 01019 case AST_FRAME_VOICE: 01020 case AST_FRAME_IMAGE: 01021 case AST_FRAME_TEXT: 01022 if (ast_write(in, f)) { 01023 ast_log(LOG_WARNING, "Unable to write frame\n"); 01024 } 01025 break; 01026 case AST_FRAME_HTML: 01027 if (!ast_test_flag64(outgoing, DIAL_NOFORWARDHTML) && ast_channel_sendhtml(in, f->subclass, f->data.ptr, f->datalen) == -1) { 01028 ast_log(LOG_WARNING, "Unable to send URL\n"); 01029 } 01030 break; 01031 default: 01032 break; 01033 } 01034 } 01035 ast_frfree(f); 01036 } /* end for */ 01037 if (winner == in) { 01038 struct ast_frame *f = ast_read(in); 01039 #if 0 01040 if (f && (f->frametype != AST_FRAME_VOICE)) 01041 printf("Frame type: %d, %d\n", f->frametype, f->subclass); 01042 else if (!f || (f->frametype != AST_FRAME_VOICE)) 01043 printf("Hangup received on %s\n", in->name); 01044 #endif 01045 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) { 01046 /* Got hung up */ 01047 *to = -1; 01048 strcpy(pa->status, "CANCEL"); 01049 ast_cdr_noanswer(in->cdr); 01050 if (f) { 01051 if (f->data.uint32) { 01052 in->hangupcause = f->data.uint32; 01053 } 01054 ast_frfree(f); 01055 } 01056 return NULL; 01057 } 01058 01059 /* now f is guaranteed non-NULL */ 01060 if (f->frametype == AST_FRAME_DTMF) { 01061 if (ast_test_flag64(peerflags, OPT_DTMF_EXIT)) { 01062 const char *context; 01063 ast_channel_lock(in); 01064 context = pbx_builtin_getvar_helper(in, "EXITCONTEXT"); 01065 if (onedigit_goto(in, context, (char) f->subclass, 1)) { 01066 ast_verb(3, "User hit %c to disconnect call.\n", f->subclass); 01067 *to = 0; 01068 ast_cdr_noanswer(in->cdr); 01069 *result = f->subclass; 01070 strcpy(pa->status, "CANCEL"); 01071 ast_frfree(f); 01072 ast_channel_unlock(in); 01073 return NULL; 01074 } 01075 ast_channel_unlock(in); 01076 } 01077 01078 if (ast_test_flag64(peerflags, OPT_CALLER_HANGUP) && 01079 (f->subclass == '*')) { /* hmm it it not guaranteed to be '*' anymore. */ 01080 ast_verb(3, "User hit %c to disconnect call.\n", f->subclass); 01081 *to = 0; 01082 strcpy(pa->status, "CANCEL"); 01083 ast_cdr_noanswer(in->cdr); 01084 ast_frfree(f); 01085 return NULL; 01086 } 01087 } 01088 01089 /* Forward HTML stuff */ 01090 if (single && (f->frametype == AST_FRAME_HTML) && !ast_test_flag64(outgoing, DIAL_NOFORWARDHTML)) 01091 if (ast_channel_sendhtml(outgoing->chan, f->subclass, f->data.ptr, f->datalen) == -1) 01092 ast_log(LOG_WARNING, "Unable to send URL\n"); 01093 01094 if (single && ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_DTMF_BEGIN) || (f->frametype == AST_FRAME_DTMF_END))) { 01095 if (ast_write(outgoing->chan, f)) 01096 ast_log(LOG_WARNING, "Unable to forward voice or dtmf\n"); 01097 } 01098 if (single && (f->frametype == AST_FRAME_CONTROL) && 01099 ((f->subclass == AST_CONTROL_HOLD) || 01100 (f->subclass == AST_CONTROL_UNHOLD) || 01101 (f->subclass == AST_CONTROL_VIDUPDATE) || 01102 (f->subclass == AST_CONTROL_SRCUPDATE))) { 01103 ast_verb(3, "%s requested special control %d, passing it to %s\n", in->name, f->subclass, outgoing->chan->name); 01104 ast_indicate_data(outgoing->chan, f->subclass, f->data.ptr, f->datalen); 01105 } 01106 ast_frfree(f); 01107 } 01108 if (!*to) 01109 ast_verb(3, "Nobody picked up in %d ms\n", orig); 01110 if (!*to || ast_check_hangup(in)) 01111 ast_cdr_noanswer(in->cdr); 01112 } 01113 01114 #ifdef HAVE_EPOLL 01115 for (epollo = outgoing; epollo; epollo = epollo->next) { 01116 if (epollo->chan) 01117 ast_poll_channel_del(in, epollo->chan); 01118 } 01119 #endif 01120 01121 return peer; 01122 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Dialing Application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, } [static] |
Definition at line 2486 of file app_dial.c.
char* app = "Dial" [static] |
Definition at line 463 of file app_dial.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 2486 of file app_dial.c.
struct ast_app_option dial_exec_options[128] = { [ 'A' ] = { .flag = OPT_ANNOUNCE , .arg_index = OPT_ARG_ANNOUNCE + 1 }, [ 'C' ] = { .flag = OPT_RESETCDR }, [ 'c' ] = { .flag = ((uint64_t)1 << 33) }, [ 'd' ] = { .flag = OPT_DTMF_EXIT }, [ 'D' ] = { .flag = OPT_SENDDTMF , .arg_index = OPT_ARG_SENDDTMF + 1 }, [ 'e' ] = { .flag = ((uint64_t)1 << 34) }, [ 'f' ] = { .flag = OPT_FORCECLID }, [ 'F' ] = { .flag = ((uint64_t)1 << 35) , .arg_index = OPT_ARG_CALLEE_GO_ON + 1 }, [ 'g' ] = { .flag = OPT_GO_ON }, [ 'G' ] = { .flag = OPT_GOTO , .arg_index = OPT_ARG_GOTO + 1 }, [ 'h' ] = { .flag = OPT_CALLEE_HANGUP }, [ 'H' ] = { .flag = OPT_CALLER_HANGUP }, [ 'i' ] = { .flag = OPT_IGNORE_FORWARDING }, [ 'k' ] = { .flag = OPT_CALLEE_PARK }, [ 'K' ] = { .flag = OPT_CALLER_PARK }, [ 'L' ] = { .flag = OPT_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, [ 'm' ] = { .flag = OPT_MUSICBACK , .arg_index = OPT_ARG_MUSICBACK + 1 }, [ 'M' ] = { .flag = OPT_CALLEE_MACRO , .arg_index = OPT_ARG_CALLEE_MACRO + 1 }, [ 'n' ] = { .flag = OPT_SCREEN_NOINTRO , .arg_index = OPT_ARG_SCREEN_NOINTRO + 1 }, [ 'N' ] = { .flag = OPT_SCREEN_NOCLID }, [ 'o' ] = { .flag = OPT_ORIGINAL_CLID }, [ 'O' ] = { .flag = OPT_OPERMODE , .arg_index = OPT_ARG_OPERMODE + 1 }, [ 'p' ] = { .flag = OPT_SCREENING }, [ 'P' ] = { .flag = OPT_PRIVACY , .arg_index = OPT_ARG_PRIVACY + 1 }, [ 'r' ] = { .flag = OPT_RINGBACK }, [ 'S' ] = { .flag = OPT_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 't' ] = { .flag = OPT_CALLEE_TRANSFER }, [ 'T' ] = { .flag = OPT_CALLER_TRANSFER }, [ 'U' ] = { .flag = OPT_CALLEE_GOSUB , .arg_index = OPT_ARG_CALLEE_GOSUB + 1 }, [ 'w' ] = { .flag = OPT_CALLEE_MONITOR }, [ 'W' ] = { .flag = OPT_CALLER_MONITOR }, [ 'x' ] = { .flag = OPT_CALLEE_MIXMONITOR }, [ 'X' ] = { .flag = OPT_CALLER_MIXMONITOR }, } [static] |
Definition at line 556 of file app_dial.c.
Referenced by dial_exec_full().
char* rapp = "RetryDial" [static] |
Definition at line 464 of file app_dial.c.
1.6.2