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_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) } |
| 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 } |
Functions | |
| static void | __reg_module (void) |
| static void | __unreg_module (void) |
| static int | detect_disconnect (struct ast_channel *chan, char code, struct ast_str *featurecode) |
| 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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, } |
| static char * | app = "Dial" |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static char * | descrip |
| 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" |
| static char * | rdescrip |
| static char * | rsynopsis = "Place a call, retrying on failure allowing optional exit extension." |
| static char * | synopsis = "Place a call and connect to the current channel" |
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 379 of file app_dial.c.
| #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 345 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 287 of file app_dial.c.
Referenced by dial_exec_full(), and wait_for_answer().
| #define DIAL_STILLGOING (1 << 31) |
Definition at line 286 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 290 of file app_dial.c.
Referenced by dial_exec_full().
| #define OPT_CANCEL_ELSEWHERE ((uint64_t)1 << 33) |
Definition at line 288 of file app_dial.c.
Referenced by dial_exec_full().
| #define OPT_PEER_H ((uint64_t)1 << 34) |
Definition at line 289 of file app_dial.c.
Referenced by dial_exec_full().
| #define S_REPLACE | ( | s, | |||
| new_val | ) |
| anonymous enum |
Definition at line 253 of file app_dial.c.
00253 { 00254 OPT_ANNOUNCE = (1 << 0), 00255 OPT_RESETCDR = (1 << 1), 00256 OPT_DTMF_EXIT = (1 << 2), 00257 OPT_SENDDTMF = (1 << 3), 00258 OPT_FORCECLID = (1 << 4), 00259 OPT_GO_ON = (1 << 5), 00260 OPT_CALLEE_HANGUP = (1 << 6), 00261 OPT_CALLER_HANGUP = (1 << 7), 00262 OPT_DURATION_LIMIT = (1 << 9), 00263 OPT_MUSICBACK = (1 << 10), 00264 OPT_CALLEE_MACRO = (1 << 11), 00265 OPT_SCREEN_NOINTRO = (1 << 12), 00266 OPT_SCREEN_NOCLID = (1 << 13), 00267 OPT_ORIGINAL_CLID = (1 << 14), 00268 OPT_SCREENING = (1 << 15), 00269 OPT_PRIVACY = (1 << 16), 00270 OPT_RINGBACK = (1 << 17), 00271 OPT_DURATION_STOP = (1 << 18), 00272 OPT_CALLEE_TRANSFER = (1 << 19), 00273 OPT_CALLER_TRANSFER = (1 << 20), 00274 OPT_CALLEE_MONITOR = (1 << 21), 00275 OPT_CALLER_MONITOR = (1 << 22), 00276 OPT_GOTO = (1 << 23), 00277 OPT_OPERMODE = (1 << 24), 00278 OPT_CALLEE_PARK = (1 << 25), 00279 OPT_CALLER_PARK = (1 << 26), 00280 OPT_IGNORE_FORWARDING = (1 << 27), 00281 OPT_CALLEE_GOSUB = (1 << 28), 00282 OPT_CALLEE_MIXMONITOR = (1 << 29), 00283 OPT_CALLER_MIXMONITOR = (1 << 30), 00284 };
| anonymous enum |
Definition at line 292 of file app_dial.c.
00292 { 00293 OPT_ARG_ANNOUNCE = 0, 00294 OPT_ARG_SENDDTMF, 00295 OPT_ARG_GOTO, 00296 OPT_ARG_DURATION_LIMIT, 00297 OPT_ARG_MUSICBACK, 00298 OPT_ARG_CALLEE_MACRO, 00299 OPT_ARG_CALLEE_GOSUB, 00300 OPT_ARG_CALLEE_GO_ON, 00301 OPT_ARG_PRIVACY, 00302 OPT_ARG_DURATION_STOP, 00303 OPT_ARG_OPERMODE, 00304 OPT_ARG_SCREEN_NOINTRO, 00305 /* note: this entry _MUST_ be the last one in the enum */ 00306 OPT_ARG_ARRAY_SIZE, 00307 };
| static void __reg_module | ( | void | ) | [static] |
Definition at line 2284 of file app_dial.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 2284 of file app_dial.c.
| static int detect_disconnect | ( | struct ast_channel * | chan, | |
| char | code, | |||
| struct ast_str * | featurecode | |||
| ) | [static] |
Definition at line 908 of file app_dial.c.
References ast_feature_detect(), AST_FEATURE_DISCONNECT, AST_FEATURE_RETURN_STOREDIGITS, ast_str_append(), ast_str_buffer, ast_str_reset(), and ast_call_feature::feature_mask.
Referenced by wait_for_answer().
00909 { 00910 struct ast_flags features = { AST_FEATURE_DISCONNECT }; /* only concerned with disconnect feature */ 00911 struct ast_call_feature feature = { 0, }; 00912 int res; 00913 00914 ast_str_append(&featurecode, 1, "%c", code); 00915 00916 res = ast_feature_detect(chan, &features, ast_str_buffer(featurecode), &feature); 00917 00918 if (res != AST_FEATURE_RETURN_STOREDIGITS) { 00919 ast_str_reset(featurecode); 00920 } 00921 if (feature.feature_mask & AST_FEATURE_DISCONNECT) { 00922 return 1; 00923 } 00924 00925 return 0; 00926 }
| static int dial_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 2134 of file app_dial.c.
References dial_exec_full().
Referenced by load_module().
02135 { 02136 struct ast_flags64 peerflags; 02137 02138 memset(&peerflags, 0, sizeof(peerflags)); 02139 02140 return dial_exec_full(chan, data, &peerflags, NULL); 02141 }
| static int dial_exec_full | ( | struct ast_channel * | chan, | |
| void * | data, | |||
| struct ast_flags64 * | peerflags, | |||
| int * | continue_exec | |||
| ) | [static] |
Definition at line 1319 of file app_dial.c.
References __ast_answer(), ast_channel::_state, 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_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_strdupa, 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, 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, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_channel::macrocontext, ast_channel::macroexten, oprmode::mode, moh, musicclass, 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, strsep(), ast_frame::subclass, ast_channel::tech, ast_channel::timingfunc, ast_channel::transfercapability, ast_channel_tech::type, url, wait_for_answer(), ast_bridge_config::warning_sound, and ast_channel::whentohangup.
Referenced by dial_exec(), and retrydial_exec().
01320 { 01321 int res = -1; /* default: error */ 01322 char *rest, *cur; /* scan the list of destinations */ 01323 struct chanlist *outgoing = NULL; /* list of destinations */ 01324 struct ast_channel *peer; 01325 int to; /* timeout */ 01326 struct cause_args num = { chan, 0, 0, 0 }; 01327 int cause; 01328 char numsubst[256]; 01329 char cidname[AST_MAX_EXTENSION] = ""; 01330 01331 struct ast_bridge_config config = { { 0, } }; 01332 struct timeval calldurationlimit = { 0, }; 01333 char *dtmfcalled = NULL, *dtmfcalling = NULL; 01334 struct privacy_args pa = { 01335 .sentringing = 0, 01336 .privdb_val = 0, 01337 .status = "INVALIDARGS", 01338 }; 01339 int sentringing = 0, moh = 0; 01340 const char *outbound_group = NULL; 01341 int result = 0; 01342 char *parse; 01343 int opermode = 0; 01344 int delprivintro = 0; 01345 AST_DECLARE_APP_ARGS(args, 01346 AST_APP_ARG(peers); 01347 AST_APP_ARG(timeout); 01348 AST_APP_ARG(options); 01349 AST_APP_ARG(url); 01350 ); 01351 struct ast_flags64 opts = { 0, }; 01352 char *opt_args[OPT_ARG_ARRAY_SIZE]; 01353 struct ast_datastore *datastore = NULL; 01354 int fulldial = 0, num_dialed = 0; 01355 01356 /* Reset all DIAL variables back to blank, to prevent confusion (in case we don't reset all of them). */ 01357 pbx_builtin_setvar_helper(chan, "DIALSTATUS", ""); 01358 pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", ""); 01359 pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", ""); 01360 pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", ""); 01361 pbx_builtin_setvar_helper(chan, "DIALEDTIME", ""); 01362 01363 if (ast_strlen_zero(data)) { 01364 ast_log(LOG_WARNING, "Dial requires an argument (technology/number)\n"); 01365 pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status); 01366 return -1; 01367 } 01368 01369 parse = ast_strdupa(data); 01370 01371 AST_STANDARD_APP_ARGS(args, parse); 01372 01373 if (!ast_strlen_zero(args.options) && 01374 ast_app_parse_options64(dial_exec_options, &opts, opt_args, args.options)) { 01375 pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status); 01376 goto done; 01377 } 01378 01379 if (ast_strlen_zero(args.peers)) { 01380 ast_log(LOG_WARNING, "Dial requires an argument (technology/number)\n"); 01381 pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status); 01382 goto done; 01383 } 01384 01385 if (ast_test_flag64(&opts, OPT_SCREEN_NOINTRO) && !ast_strlen_zero(opt_args[OPT_ARG_SCREEN_NOINTRO])) { 01386 delprivintro = atoi(opt_args[OPT_ARG_SCREEN_NOINTRO]); 01387 if (delprivintro < 0 || delprivintro > 1) { 01388 ast_log(LOG_WARNING, "Unknown argument %d to n option, ignoring\n", delprivintro); 01389 delprivintro = 0; 01390 } 01391 } 01392 01393 if (ast_test_flag64(&opts, OPT_OPERMODE)) { 01394 opermode = ast_strlen_zero(opt_args[OPT_ARG_OPERMODE]) ? 1 : atoi(opt_args[OPT_ARG_OPERMODE]); 01395 ast_verb(3, "Setting operator services mode to %d.\n", opermode); 01396 } 01397 01398 if (ast_test_flag64(&opts, OPT_DURATION_STOP) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_STOP])) { 01399 calldurationlimit.tv_sec = atoi(opt_args[OPT_ARG_DURATION_STOP]); 01400 if (!calldurationlimit.tv_sec) { 01401 ast_log(LOG_WARNING, "Dial does not accept S(%s), hanging up.\n", opt_args[OPT_ARG_DURATION_STOP]); 01402 pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status); 01403 goto done; 01404 } 01405 ast_verb(3, "Setting call duration limit to %.3lf seconds.\n", calldurationlimit.tv_sec + calldurationlimit.tv_usec / 1000000.0); 01406 } 01407 01408 if (ast_test_flag64(&opts, OPT_SENDDTMF) && !ast_strlen_zero(opt_args[OPT_ARG_SENDDTMF])) { 01409 dtmfcalling = opt_args[OPT_ARG_SENDDTMF]; 01410 dtmfcalled = strsep(&dtmfcalling, ":"); 01411 } 01412 01413 if (ast_test_flag64(&opts, OPT_DURATION_LIMIT) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])) { 01414 if (do_timelimit(chan, &config, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit)) 01415 goto done; 01416 } 01417 01418 if (ast_test_flag64(&opts, OPT_RESETCDR) && chan->cdr) 01419 ast_cdr_reset(chan->cdr, NULL); 01420 if (ast_test_flag64(&opts, OPT_PRIVACY) && ast_strlen_zero(opt_args[OPT_ARG_PRIVACY])) 01421 opt_args[OPT_ARG_PRIVACY] = ast_strdupa(chan->exten); 01422 01423 if (ast_test_flag64(&opts, OPT_PRIVACY) || ast_test_flag64(&opts, OPT_SCREENING)) { 01424 res = setup_privacy_args(&pa, &opts, opt_args, chan); 01425 if (res <= 0) 01426 goto out; 01427 res = -1; /* reset default */ 01428 } 01429 01430 if (ast_test_flag64(&opts, OPT_DTMF_EXIT) || ast_test_flag64(&opts, OPT_CALLER_HANGUP)) { 01431 __ast_answer(chan, 0, 0); 01432 } 01433 01434 if (continue_exec) 01435 *continue_exec = 0; 01436 01437 /* If a channel group has been specified, get it for use when we create peer channels */ 01438 01439 ast_channel_lock(chan); 01440 if ((outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP_ONCE"))) { 01441 outbound_group = ast_strdupa(outbound_group); 01442 pbx_builtin_setvar_helper(chan, "OUTBOUND_GROUP_ONCE", NULL); 01443 } else if ((outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP"))) { 01444 outbound_group = ast_strdupa(outbound_group); 01445 } 01446 ast_channel_unlock(chan); 01447 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); 01448 01449 /* loop through the list of dial destinations */ 01450 rest = args.peers; 01451 while ((cur = strsep(&rest, "&")) ) { 01452 struct chanlist *tmp; 01453 struct ast_channel *tc; /* channel for this destination */ 01454 /* Get a technology/[device:]number pair */ 01455 char *number = cur; 01456 char *interface = ast_strdupa(number); 01457 char *tech = strsep(&number, "/"); 01458 /* find if we already dialed this interface */ 01459 struct ast_dialed_interface *di; 01460 AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces; 01461 num_dialed++; 01462 if (!number) { 01463 ast_log(LOG_WARNING, "Dial argument takes format (technology/[device:]number1)\n"); 01464 goto out; 01465 } 01466 if (!(tmp = ast_calloc(1, sizeof(*tmp)))) 01467 goto out; 01468 if (opts.flags) { 01469 ast_copy_flags64(tmp, &opts, 01470 OPT_CANCEL_ELSEWHERE | 01471 OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER | 01472 OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP | 01473 OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR | 01474 OPT_CALLEE_PARK | OPT_CALLER_PARK | 01475 OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR | 01476 OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID); 01477 ast_set2_flag64(tmp, args.url, DIAL_NOFORWARDHTML); 01478 } 01479 ast_copy_string(numsubst, number, sizeof(numsubst)); 01480 /* Request the peer */ 01481 01482 ast_channel_lock(chan); 01483 datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL); 01484 ast_channel_unlock(chan); 01485 01486 if (datastore) 01487 dialed_interfaces = datastore->data; 01488 else { 01489 if (!(datastore = ast_datastore_alloc(&dialed_interface_info, NULL))) { 01490 ast_log(LOG_WARNING, "Unable to create channel datastore for dialed interfaces. Aborting!\n"); 01491 ast_free(tmp); 01492 goto out; 01493 } 01494 01495 datastore->inheritance = DATASTORE_INHERIT_FOREVER; 01496 01497 if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) { 01498 ast_datastore_free(datastore); 01499 ast_free(tmp); 01500 goto out; 01501 } 01502 01503 datastore->data = dialed_interfaces; 01504 AST_LIST_HEAD_INIT(dialed_interfaces); 01505 01506 ast_channel_lock(chan); 01507 ast_channel_datastore_add(chan, datastore); 01508 ast_channel_unlock(chan); 01509 } 01510 01511 AST_LIST_LOCK(dialed_interfaces); 01512 AST_LIST_TRAVERSE(dialed_interfaces, di, list) { 01513 if (!strcasecmp(di->interface, interface)) { 01514 ast_log(LOG_WARNING, "Skipping dialing interface '%s' again since it has already been dialed\n", 01515 di->interface); 01516 break; 01517 } 01518 } 01519 AST_LIST_UNLOCK(dialed_interfaces); 01520 01521 if (di) { 01522 fulldial++; 01523 ast_free(tmp); 01524 continue; 01525 } 01526 01527 /* It is always ok to dial a Local interface. We only keep track of 01528 * which "real" interfaces have been dialed. The Local channel will 01529 * inherit this list so that if it ends up dialing a real interface, 01530 * it won't call one that has already been called. */ 01531 if (strcasecmp(tech, "Local")) { 01532 if (!(di = ast_calloc(1, sizeof(*di) + strlen(interface)))) { 01533 AST_LIST_UNLOCK(dialed_interfaces); 01534 ast_free(tmp); 01535 goto out; 01536 } 01537 strcpy(di->interface, interface); 01538 01539 AST_LIST_LOCK(dialed_interfaces); 01540 AST_LIST_INSERT_TAIL(dialed_interfaces, di, list); 01541 AST_LIST_UNLOCK(dialed_interfaces); 01542 } 01543 01544 tc = ast_request(tech, chan->nativeformats, numsubst, &cause); 01545 if (!tc) { 01546 /* If we can't, just go on to the next call */ 01547 ast_log(LOG_WARNING, "Unable to create channel of type '%s' (cause %d - %s)\n", 01548 tech, cause, ast_cause2str(cause)); 01549 handle_cause(cause, &num); 01550 if (!rest) /* we are on the last destination */ 01551 chan->hangupcause = cause; 01552 ast_free(tmp); 01553 continue; 01554 } 01555 pbx_builtin_setvar_helper(tc, "DIALEDPEERNUMBER", numsubst); 01556 01557 /* Setup outgoing SDP to match incoming one */ 01558 if (CAN_EARLY_BRIDGE(peerflags, chan, tc)) { 01559 ast_rtp_make_compatible(tc, chan, !outgoing && !rest); 01560 } 01561 01562 /* Inherit specially named variables from parent channel */ 01563 ast_channel_inherit_variables(chan, tc); 01564 ast_channel_datastore_inherit(chan, tc); 01565 01566 tc->appl = "AppDial"; 01567 tc->data = "(Outgoing Line)"; 01568 memset(&tc->whentohangup, 0, sizeof(tc->whentohangup)); 01569 01570 S_REPLACE(tc->cid.cid_num, ast_strdup(chan->cid.cid_num)); 01571 S_REPLACE(tc->cid.cid_name, ast_strdup(chan->cid.cid_name)); 01572 S_REPLACE(tc->cid.cid_ani, ast_strdup(chan->cid.cid_ani)); 01573 S_REPLACE(tc->cid.cid_rdnis, ast_strdup(chan->cid.cid_rdnis)); 01574 01575 ast_string_field_set(tc, accountcode, chan->accountcode); 01576 tc->cdrflags = chan->cdrflags; 01577 if (ast_strlen_zero(tc->musicclass)) 01578 ast_string_field_set(tc, musicclass, chan->musicclass); 01579 /* Pass callingpres, type of number, tns, ADSI CPE, transfer capability */ 01580 tc->cid.cid_pres = chan->cid.cid_pres; 01581 tc->cid.cid_ton = chan->cid.cid_ton; 01582 tc->cid.cid_tns = chan->cid.cid_tns; 01583 tc->cid.cid_ani2 = chan->cid.cid_ani2; 01584 tc->adsicpe = chan->adsicpe; 01585 tc->transfercapability = chan->transfercapability; 01586 01587 /* If we have an outbound group, set this peer channel to it */ 01588 if (outbound_group) 01589 ast_app_group_set_channel(tc, outbound_group); 01590 01591 /* Inherit context and extension */ 01592 ast_string_field_set(tc, dialcontext, ast_strlen_zero(chan->macrocontext) ? chan->context : chan->macrocontext); 01593 if (!ast_strlen_zero(chan->macroexten)) 01594 ast_copy_string(tc->exten, chan->macroexten, sizeof(tc->exten)); 01595 else 01596 ast_copy_string(tc->exten, chan->exten, sizeof(tc->exten)); 01597 01598 res = ast_call(tc, numsubst, 0); /* Place the call, but don't wait on the answer */ 01599 01600 /* Save the info in cdr's that we called them */ 01601 if (chan->cdr) 01602 ast_cdr_setdestchan(chan->cdr, tc->name); 01603 01604 /* check the results of ast_call */ 01605 if (res) { 01606 /* Again, keep going even if there's an error */ 01607 ast_debug(1, "ast call on peer returned %d\n", res); 01608 ast_verb(3, "Couldn't call %s\n", numsubst); 01609 if (tc->hangupcause) { 01610 chan->hangupcause = tc->hangupcause; 01611 } 01612 ast_hangup(tc); 01613 tc = NULL; 01614 ast_free(tmp); 01615 continue; 01616 } else { 01617 senddialevent(chan, tc, numsubst); 01618 ast_verb(3, "Called %s\n", numsubst); 01619 if (!ast_test_flag64(peerflags, OPT_ORIGINAL_CLID)) 01620 ast_set_callerid(tc, S_OR(chan->macroexten, chan->exten), get_cid_name(cidname, sizeof(cidname), chan), NULL); 01621 } 01622 /* Put them in the list of outgoing thingies... We're ready now. 01623 XXX If we're forcibly removed, these outgoing calls won't get 01624 hung up XXX */ 01625 ast_set_flag64(tmp, DIAL_STILLGOING); 01626 tmp->chan = tc; 01627 tmp->next = outgoing; 01628 outgoing = tmp; 01629 /* If this line is up, don't try anybody else */ 01630 if (outgoing->chan->_state == AST_STATE_UP) 01631 break; 01632 } 01633 01634 if (ast_strlen_zero(args.timeout)) { 01635 to = -1; 01636 } else { 01637 to = atoi(args.timeout); 01638 if (to > 0) 01639 to *= 1000; 01640 else { 01641 ast_log(LOG_WARNING, "Invalid timeout specified: '%s'. Setting timeout to infinite\n", args.timeout); 01642 to = -1; 01643 } 01644 } 01645 01646 if (!outgoing) { 01647 strcpy(pa.status, "CHANUNAVAIL"); 01648 if (fulldial == num_dialed) { 01649 res = -1; 01650 goto out; 01651 } 01652 } else { 01653 /* Our status will at least be NOANSWER */ 01654 strcpy(pa.status, "NOANSWER"); 01655 if (ast_test_flag64(outgoing, OPT_MUSICBACK)) { 01656 moh = 1; 01657 if (!ast_strlen_zero(opt_args[OPT_ARG_MUSICBACK])) { 01658 char *original_moh = ast_strdupa(chan->musicclass); 01659 ast_string_field_set(chan, musicclass, opt_args[OPT_ARG_MUSICBACK]); 01660 ast_moh_start(chan, opt_args[OPT_ARG_MUSICBACK], NULL); 01661 ast_string_field_set(chan, musicclass, original_moh); 01662 } else { 01663 ast_moh_start(chan, NULL, NULL); 01664 } 01665 ast_indicate(chan, AST_CONTROL_PROGRESS); 01666 } else if (ast_test_flag64(outgoing, OPT_RINGBACK)) { 01667 ast_indicate(chan, AST_CONTROL_RINGING); 01668 sentringing++; 01669 } 01670 } 01671 01672 peer = wait_for_answer(chan, outgoing, &to, peerflags, &pa, &num, &result); 01673 01674 /* The ast_channel_datastore_remove() function could fail here if the 01675 * datastore was moved to another channel during a masquerade. If this is 01676 * the case, don't free the datastore here because later, when the channel 01677 * to which the datastore was moved hangs up, it will attempt to free this 01678 * datastore again, causing a crash 01679 */ 01680 if (!ast_channel_datastore_remove(chan, datastore)) 01681 ast_datastore_free(datastore); 01682 if (!peer) { 01683 if (result) { 01684 res = result; 01685 } else if (to) { /* Musta gotten hung up */ 01686 res = -1; 01687 } else { /* Nobody answered, next please? */ 01688 res = 0; 01689 } 01690 01691 /* SIP, in particular, sends back this error code to indicate an 01692 * overlap dialled number needs more digits. */ 01693 if (chan->hangupcause == AST_CAUSE_INVALID_NUMBER_FORMAT) { 01694 res = AST_PBX_INCOMPLETE; 01695 } 01696 01697 /* almost done, although the 'else' block is 400 lines */ 01698 } else { 01699 const char *number; 01700 01701 strcpy(pa.status, "ANSWER"); 01702 pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status); 01703 /* Ah ha! Someone answered within the desired timeframe. Of course after this 01704 we will always return with -1 so that it is hung up properly after the 01705 conversation. */ 01706 hanguptree(outgoing, peer, 1); 01707 outgoing = NULL; 01708 /* If appropriate, log that we have a destination channel */ 01709 if (chan->cdr) 01710 ast_cdr_setdestchan(chan->cdr, peer->name); 01711 if (peer->name) 01712 pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", peer->name); 01713 01714 ast_channel_lock(peer); 01715 number = pbx_builtin_getvar_helper(peer, "DIALEDPEERNUMBER"); 01716 if (!number) 01717 number = numsubst; 01718 pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", number); 01719 ast_channel_unlock(peer); 01720 01721 if (!ast_strlen_zero(args.url) && ast_channel_supports_html(peer) ) { 01722 ast_debug(1, "app_dial: sendurl=%s.\n", args.url); 01723 ast_channel_sendurl( peer, args.url ); 01724 } 01725 if ( (ast_test_flag64(&opts, OPT_PRIVACY) || ast_test_flag64(&opts, OPT_SCREENING)) && pa.privdb_val == AST_PRIVACY_UNKNOWN) { 01726 if (do_privacy(chan, peer, &opts, opt_args, &pa)) { 01727 res = 0; 01728 goto out; 01729 } 01730 } 01731 if (!ast_test_flag64(&opts, OPT_ANNOUNCE) || ast_strlen_zero(opt_args[OPT_ARG_ANNOUNCE])) { 01732 res = 0; 01733 } else { 01734 int digit = 0; 01735 struct ast_channel *chans[2]; 01736 struct ast_channel *active_chan; 01737 01738 chans[0] = chan; 01739 chans[1] = peer; 01740 01741 /* we need to stream the announcment while monitoring the caller for a hangup */ 01742 01743 /* stream the file */ 01744 res = ast_streamfile(peer, opt_args[OPT_ARG_ANNOUNCE], peer->language); 01745 if (res) { 01746 res = 0; 01747 ast_log(LOG_ERROR, "error streaming file '%s' to callee\n", opt_args[OPT_ARG_ANNOUNCE]); 01748 } 01749 01750 ast_set_flag(peer, AST_FLAG_END_DTMF_ONLY); 01751 while (peer->stream) { 01752 int ms; 01753 01754 ms = ast_sched_wait(peer->sched); 01755 01756 if (ms < 0 && !peer->timingfunc) { 01757 ast_stopstream(peer); 01758 break; 01759 } 01760 if (ms < 0) 01761 ms = 1000; 01762 01763 active_chan = ast_waitfor_n(chans, 2, &ms); 01764 if (active_chan) { 01765 struct ast_frame *fr = ast_read(active_chan); 01766 if (!fr) { 01767 ast_hangup(peer); 01768 res = -1; 01769 goto done; 01770 } 01771 switch(fr->frametype) { 01772 case AST_FRAME_DTMF_END: 01773 digit = fr->subclass; 01774 if (active_chan == peer && strchr(AST_DIGIT_ANY, res)) { 01775 ast_stopstream(peer); 01776 res = ast_senddigit(chan, digit, 0); 01777 } 01778 break; 01779 case AST_FRAME_CONTROL: 01780 switch (fr->subclass) { 01781 case AST_CONTROL_HANGUP: 01782 ast_frfree(fr); 01783 ast_hangup(peer); 01784 res = -1; 01785 goto done; 01786 default: 01787 break; 01788 } 01789 break; 01790 default: 01791 /* Ignore all others */ 01792 break; 01793 } 01794 ast_frfree(fr); 01795 } 01796 ast_sched_runq(peer->sched); 01797 } 01798 ast_clear_flag(peer, AST_FLAG_END_DTMF_ONLY); 01799 } 01800 01801 if (chan && peer && ast_test_flag64(&opts, OPT_GOTO) && !ast_strlen_zero(opt_args[OPT_ARG_GOTO])) { 01802 replace_macro_delimiter(opt_args[OPT_ARG_GOTO]); 01803 ast_parseable_goto(chan, opt_args[OPT_ARG_GOTO]); 01804 /* peer goes to the same context and extension as chan, so just copy info from chan*/ 01805 ast_copy_string(peer->context, chan->context, sizeof(peer->context)); 01806 ast_copy_string(peer->exten, chan->exten, sizeof(peer->exten)); 01807 peer->priority = chan->priority + 2; 01808 ast_pbx_start(peer); 01809 hanguptree(outgoing, NULL, ast_test_flag64(&opts, OPT_CANCEL_ELSEWHERE) ? 1 : 0); 01810 if (continue_exec) 01811 *continue_exec = 1; 01812 res = 0; 01813 goto done; 01814 } 01815 01816 if (ast_test_flag64(&opts, OPT_CALLEE_MACRO) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_MACRO])) { 01817 struct ast_app *theapp; 01818 const char *macro_result; 01819 01820 res = ast_autoservice_start(chan); 01821 if (res) { 01822 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n"); 01823 res = -1; 01824 } 01825 01826 theapp = pbx_findapp("Macro"); 01827 01828 if (theapp && !res) { /* XXX why check res here ? */ 01829 /* Set peer->exten and peer->context so that MACRO_EXTEN and MACRO_CONTEXT get set */ 01830 ast_copy_string(peer->context, chan->context, sizeof(peer->context)); 01831 ast_copy_string(peer->exten, chan->exten, sizeof(peer->exten)); 01832 01833 replace_macro_delimiter(opt_args[OPT_ARG_CALLEE_MACRO]); 01834 res = pbx_exec(peer, theapp, opt_args[OPT_ARG_CALLEE_MACRO]); 01835 ast_debug(1, "Macro exited with status %d\n", res); 01836 res = 0; 01837 } else { 01838 ast_log(LOG_ERROR, "Could not find application Macro\n"); 01839 res = -1; 01840 } 01841 01842 if (ast_autoservice_stop(chan) < 0) { 01843 res = -1; 01844 } 01845 01846 ast_channel_lock(peer); 01847 01848 if (!res && (macro_result = pbx_builtin_getvar_helper(peer, "MACRO_RESULT"))) { 01849 char *macro_transfer_dest; 01850 01851 if (!strcasecmp(macro_result, "BUSY")) { 01852 ast_copy_string(pa.status, macro_result, sizeof(pa.status)); 01853 ast_set_flag64(peerflags, OPT_GO_ON); 01854 res = -1; 01855 } else if (!strcasecmp(macro_result, "CONGESTION") || !strcasecmp(macro_result, "CHANUNAVAIL")) { 01856 ast_copy_string(pa.status, macro_result, sizeof(pa.status)); 01857 ast_set_flag64(peerflags, OPT_GO_ON); 01858 res = -1; 01859 } else if (!strcasecmp(macro_result, "CONTINUE")) { 01860 /* hangup peer and keep chan alive assuming the macro has changed 01861 the context / exten / priority or perhaps 01862 the next priority in the current exten is desired. 01863 */ 01864 ast_set_flag64(peerflags, OPT_GO_ON); 01865 res = -1; 01866 } else if (!strcasecmp(macro_result, "ABORT")) { 01867 /* Hangup both ends unless the caller has the g flag */ 01868 res = -1; 01869 } else if (!strncasecmp(macro_result, "GOTO:", 5) && (macro_transfer_dest = ast_strdupa(macro_result + 5))) { 01870 res = -1; 01871 /* perform a transfer to a new extension */ 01872 if (strchr(macro_transfer_dest, '^')) { /* context^exten^priority*/ 01873 replace_macro_delimiter(macro_transfer_dest); 01874 if (!ast_parseable_goto(chan, macro_transfer_dest)) 01875 ast_set_flag64(peerflags, OPT_GO_ON); 01876 } 01877 } 01878 } 01879 01880 ast_channel_unlock(peer); 01881 } 01882 01883 if (ast_test_flag64(&opts, OPT_CALLEE_GOSUB) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GOSUB])) { 01884 struct ast_app *theapp; 01885 const char *gosub_result; 01886 char *gosub_args, *gosub_argstart; 01887 int res9 = -1; 01888 01889 res9 = ast_autoservice_start(chan); 01890 if (res9) { 01891 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n"); 01892 res9 = -1; 01893 } 01894 01895 theapp = pbx_findapp("Gosub"); 01896 01897 if (theapp && !res9) { 01898 replace_macro_delimiter(opt_args[OPT_ARG_CALLEE_GOSUB]); 01899 01900 /* Set where we came from */ 01901 ast_copy_string(peer->context, "app_dial_gosub_virtual_context", sizeof(peer->context)); 01902 ast_copy_string(peer->exten, "s", sizeof(peer->exten)); 01903 peer->priority = 0; 01904 01905 gosub_argstart = strchr(opt_args[OPT_ARG_CALLEE_GOSUB], ','); 01906 if (gosub_argstart) { 01907 *gosub_argstart = 0; 01908 if (asprintf(&gosub_args, "%s,s,1(%s)", opt_args[OPT_ARG_CALLEE_GOSUB], gosub_argstart + 1) < 0) { 01909 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 01910 gosub_args = NULL; 01911 } 01912 *gosub_argstart = ','; 01913 } else { 01914 if (asprintf(&gosub_args, "%s,s,1", opt_args[OPT_ARG_CALLEE_GOSUB]) < 0) { 01915 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 01916 gosub_args = NULL; 01917 } 01918 } 01919 01920 if (gosub_args) { 01921 res9 = pbx_exec(peer, theapp, gosub_args); 01922 if (!res9) { 01923 struct ast_pbx_args args; 01924 /* A struct initializer fails to compile for this case ... */ 01925 memset(&args, 0, sizeof(args)); 01926 args.no_hangup_chan = 1; 01927 ast_pbx_run_args(peer, &args); 01928 } 01929 ast_free(gosub_args); 01930 ast_debug(1, "Gosub exited with status %d\n", res9); 01931 } else { 01932 ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n"); 01933 } 01934 01935 } else if (!res9) { 01936 ast_log(LOG_ERROR, "Could not find application Gosub\n"); 01937 res9 = -1; 01938 } 01939 01940 if (ast_autoservice_stop(chan) < 0) { 01941 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n"); 01942 res9 = -1; 01943 } 01944 01945 ast_channel_lock(peer); 01946 01947 if (!res9 && (gosub_result = pbx_builtin_getvar_helper(peer, "GOSUB_RESULT"))) { 01948 char *gosub_transfer_dest; 01949 01950 if (!strcasecmp(gosub_result, "BUSY")) { 01951 ast_copy_string(pa.status, gosub_result, sizeof(pa.status)); 01952 ast_set_flag64(peerflags, OPT_GO_ON); 01953 res9 = -1; 01954 } else if (!strcasecmp(gosub_result, "CONGESTION") || !strcasecmp(gosub_result, "CHANUNAVAIL")) { 01955 ast_copy_string(pa.status, gosub_result, sizeof(pa.status)); 01956 ast_set_flag64(peerflags, OPT_GO_ON); 01957 res9 = -1; 01958 } else if (!strcasecmp(gosub_result, "CONTINUE")) { 01959 /* hangup peer and keep chan alive assuming the macro has changed 01960 the context / exten / priority or perhaps 01961 the next priority in the current exten is desired. 01962 */ 01963 ast_set_flag64(peerflags, OPT_GO_ON); 01964 res9 = -1; 01965 } else if (!strcasecmp(gosub_result, "ABORT")) { 01966 /* Hangup both ends unless the caller has the g flag */ 01967 res9 = -1; 01968 } else if (!strncasecmp(gosub_result, "GOTO:", 5) && (gosub_transfer_dest = ast_strdupa(gosub_result + 5))) { 01969 res9 = -1; 01970 /* perform a transfer to a new extension */ 01971 if (strchr(gosub_transfer_dest, '^')) { /* context^exten^priority*/ 01972 replace_macro_delimiter(gosub_transfer_dest); 01973 if (!ast_parseable_goto(chan, gosub_transfer_dest)) 01974 ast_set_flag64(peerflags, OPT_GO_ON); 01975 } 01976 } 01977 } 01978 01979 ast_channel_unlock(peer); 01980 } 01981 01982 if (!res) { 01983 if (!ast_tvzero(calldurationlimit)) { 01984 struct timeval whentohangup = calldurationlimit; 01985 peer->whentohangup = ast_tvadd(ast_tvnow(), whentohangup); 01986 } 01987 if (!ast_strlen_zero(dtmfcalled)) { 01988 ast_verb(3, "Sending DTMF '%s' to the called party.\n", dtmfcalled); 01989 res = ast_dtmf_stream(peer, chan, dtmfcalled, 250, 0); 01990 } 01991 if (!ast_strlen_zero(dtmfcalling)) { 01992 ast_verb(3, "Sending DTMF '%s' to the calling party.\n", dtmfcalling); 01993 res = ast_dtmf_stream(chan, peer, dtmfcalling, 250, 0); 01994 } 01995 } 01996 01997 if (res) { /* some error */ 01998 res = -1; 01999 } else { 02000 if (ast_test_flag64(peerflags, OPT_CALLEE_TRANSFER)) 02001 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 02002 if (ast_test_flag64(peerflags, OPT_CALLER_TRANSFER)) 02003 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 02004 if (ast_test_flag64(peerflags, OPT_CALLEE_HANGUP)) 02005 ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT); 02006 if (ast_test_flag64(peerflags, OPT_CALLER_HANGUP)) 02007 ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT); 02008 if (ast_test_flag64(peerflags, OPT_CALLEE_MONITOR)) 02009 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON); 02010 if (ast_test_flag64(peerflags, OPT_CALLER_MONITOR)) 02011 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON); 02012 if (ast_test_flag64(peerflags, OPT_CALLEE_PARK)) 02013 ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL); 02014 if (ast_test_flag64(peerflags, OPT_CALLER_PARK)) 02015 ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL); 02016 if (ast_test_flag64(peerflags, OPT_CALLEE_MIXMONITOR)) 02017 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMIXMON); 02018 if (ast_test_flag64(peerflags, OPT_CALLER_MIXMONITOR)) 02019 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMIXMON); 02020 if (ast_test_flag64(peerflags, OPT_GO_ON)) 02021 ast_set_flag(&(config.features_caller), AST_FEATURE_NO_H_EXTEN); 02022 02023 config.end_bridge_callback = end_bridge_callback; 02024 config.end_bridge_callback_data = chan; 02025 config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup; 02026 02027 if (moh) { 02028 moh = 0; 02029 ast_moh_stop(chan); 02030 } else if (sentringing) { 02031 sentringing = 0; 02032 ast_indicate(chan, -1); 02033 } 02034 /* Be sure no generators are left on it */ 02035 ast_deactivate_generator(chan); 02036 /* Make sure channels are compatible */ 02037 res = ast_channel_make_compatible(chan, peer); 02038 if (res < 0) { 02039 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", chan->name, peer->name); 02040 ast_hangup(peer); 02041 res = -1; 02042 goto done; 02043 } 02044 if (opermode && !strncmp(chan->tech->type, "DAHDI", 5) && !strncmp(peer->name, "DAHDI", 5)) { 02045 /* what's this special handling for dahdi <-> dahdi ? 02046 * A: dahdi to dahdi calls are natively bridged at the kernel driver 02047 * level, so we need to ensure that this mode gets propagated 02048 * all the way down. */ 02049 struct oprmode oprmode; 02050 02051 oprmode.peer = peer; 02052 oprmode.mode = opermode; 02053 02054 ast_channel_setoption(chan, AST_OPTION_OPRMODE, &oprmode, sizeof(oprmode), 0); 02055 } 02056 res = ast_bridge_call(chan, peer, &config); 02057 } 02058 02059 strcpy(peer->context, chan->context); 02060 02061 if (ast_test_flag64(&opts, OPT_PEER_H) && ast_exists_extension(peer, peer->context, "h", 1, peer->cid.cid_num)) { 02062 int autoloopflag; 02063 int found; 02064 int res9; 02065 02066 strcpy(peer->exten, "h"); 02067 peer->priority = 1; 02068 autoloopflag = ast_test_flag(peer, AST_FLAG_IN_AUTOLOOP); /* save value to restore at the end */ 02069 ast_set_flag(peer, AST_FLAG_IN_AUTOLOOP); 02070 02071 while ((res9 = ast_spawn_extension(peer, peer->context, peer->exten, peer->priority, peer->cid.cid_num, &found, 1)) == 0) 02072 peer->priority++; 02073 02074 if (found && res9) { 02075 /* Something bad happened, or a hangup has been requested. */ 02076 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", peer->context, peer->exten, peer->priority, peer->name); 02077 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", peer->context, peer->exten, peer->priority, peer->name); 02078 } 02079 ast_set2_flag(peer, autoloopflag, AST_FLAG_IN_AUTOLOOP); /* set it back the way it was */ 02080 } 02081 if (!ast_check_hangup(peer) && ast_test_flag64(&opts, OPT_CALLEE_GO_ON) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GO_ON])) { 02082 replace_macro_delimiter(opt_args[OPT_ARG_CALLEE_GO_ON]); 02083 ast_parseable_goto(peer, opt_args[OPT_ARG_CALLEE_GO_ON]); 02084 ast_pbx_start(peer); 02085 } else { 02086 if (!ast_check_hangup(chan)) 02087 chan->hangupcause = peer->hangupcause; 02088 ast_hangup(peer); 02089 } 02090 } 02091 out: 02092 if (moh) { 02093 moh = 0; 02094 ast_moh_stop(chan); 02095 } else if (sentringing) { 02096 sentringing = 0; 02097 ast_indicate(chan, -1); 02098 } 02099 02100 if (delprivintro && ast_fileexists(pa.privintro, NULL, NULL) > 0) { 02101 ast_filedelete(pa.privintro, NULL); 02102 if (ast_fileexists(pa.privintro, NULL, NULL) > 0) { 02103 ast_log(LOG_NOTICE, "privacy: ast_filedelete didn't do its job on %s\n", pa.privintro); 02104 } else { 02105 ast_verb(3, "Successfully deleted %s intro file\n", pa.privintro); 02106 } 02107 } 02108 02109 ast_channel_early_bridge(chan, NULL); 02110 hanguptree(outgoing, NULL, 0); /* In this case, there's no answer anywhere */ 02111 pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status); 02112 senddialendevent(chan, pa.status); 02113 ast_debug(1, "Exiting with DIALSTATUS=%s.\n", pa.status); 02114 02115 if ((ast_test_flag64(peerflags, OPT_GO_ON)) && !ast_check_hangup(chan) && (res != AST_PBX_INCOMPLETE)) { 02116 if (!ast_tvzero(calldurationlimit)) 02117 memset(&chan->whentohangup, 0, sizeof(chan->whentohangup)); 02118 res = 0; 02119 } 02120 02121 done: 02122 if (config.warning_sound) { 02123 ast_free((char *)config.warning_sound); 02124 } 02125 if (config.end_sound) { 02126 ast_free((char *)config.end_sound); 02127 } 02128 if (config.start_sound) { 02129 ast_free((char *)config.start_sound); 02130 } 02131 return res; 02132 }
| 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 496 of file app_dial.c.
References 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, CAN_EARLY_BRIDGE, 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::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().
00498 { 00499 char tmpchan[256]; 00500 struct ast_channel *original = o->chan; 00501 struct ast_channel *c = o->chan; /* the winner */ 00502 struct ast_channel *in = num->chan; /* the input channel */ 00503 char *stuff; 00504 char *tech; 00505 int cause; 00506 00507 ast_copy_string(tmpchan, c->call_forward, sizeof(tmpchan)); 00508 if ((stuff = strchr(tmpchan, '/'))) { 00509 *stuff++ = '\0'; 00510 tech = tmpchan; 00511 } else { 00512 const char *forward_context; 00513 ast_channel_lock(c); 00514 forward_context = pbx_builtin_getvar_helper(c, "FORWARD_CONTEXT"); 00515 if (ast_strlen_zero(forward_context)) { 00516 forward_context = NULL; 00517 } 00518 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", c->call_forward, forward_context ? forward_context : c->context); 00519 ast_channel_unlock(c); 00520 stuff = tmpchan; 00521 tech = "Local"; 00522 } 00523 /* Before processing channel, go ahead and check for forwarding */ 00524 ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, c->name); 00525 /* If we have been told to ignore forwards, just set this channel to null and continue processing extensions normally */ 00526 if (ast_test_flag64(peerflags, OPT_IGNORE_FORWARDING)) { 00527 ast_verb(3, "Forwarding %s to '%s/%s' prevented.\n", in->name, tech, stuff); 00528 c = o->chan = NULL; 00529 cause = AST_CAUSE_BUSY; 00530 } else { 00531 /* Setup parameters */ 00532 c = o->chan = ast_request(tech, in->nativeformats, stuff, &cause); 00533 if (c) { 00534 if (single) 00535 ast_channel_make_compatible(o->chan, in); 00536 ast_channel_inherit_variables(in, o->chan); 00537 ast_channel_datastore_inherit(in, o->chan); 00538 } else 00539 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause); 00540 } 00541 if (!c) { 00542 ast_clear_flag64(o, DIAL_STILLGOING); 00543 handle_cause(cause, num); 00544 ast_hangup(original); 00545 } else { 00546 char *new_cid_num, *new_cid_name; 00547 struct ast_channel *src; 00548 00549 if (CAN_EARLY_BRIDGE(peerflags, c, in)) { 00550 ast_rtp_make_compatible(c, in, single); 00551 } 00552 if (ast_test_flag64(o, OPT_FORCECLID)) { 00553 new_cid_num = ast_strdup(S_OR(in->macroexten, in->exten)); 00554 new_cid_name = NULL; /* XXX no name ? */ 00555 src = c; /* XXX possible bug in previous code, which used 'winner' ? it may have changed */ 00556 } else { 00557 new_cid_num = ast_strdup(in->cid.cid_num); 00558 new_cid_name = ast_strdup(in->cid.cid_name); 00559 src = in; 00560 } 00561 ast_string_field_set(c, accountcode, src->accountcode); 00562 c->cdrflags = src->cdrflags; 00563 S_REPLACE(c->cid.cid_num, new_cid_num); 00564 S_REPLACE(c->cid.cid_name, new_cid_name); 00565 00566 if (in->cid.cid_ani) { /* XXX or maybe unconditional ? */ 00567 S_REPLACE(c->cid.cid_ani, ast_strdup(in->cid.cid_ani)); 00568 } 00569 S_REPLACE(c->cid.cid_rdnis, ast_strdup(S_OR(in->macroexten, in->exten))); 00570 if (ast_call(c, tmpchan, 0)) { 00571 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan); 00572 ast_clear_flag64(o, DIAL_STILLGOING); 00573 ast_hangup(original); 00574 ast_hangup(c); 00575 c = o->chan = NULL; 00576 num->nochan++; 00577 } else { 00578 senddialevent(in, c, stuff); 00579 /* After calling, set callerid to extension */ 00580 if (!ast_test_flag64(peerflags, OPT_ORIGINAL_CLID)) { 00581 char cidname[AST_MAX_EXTENSION] = ""; 00582 ast_set_callerid(c, S_OR(in->macroexten, in->exten), get_cid_name(cidname, sizeof(cidname), in), NULL); 00583 } 00584 /* Hangup the original channel now, in case we needed it */ 00585 ast_hangup(original); 00586 } 00587 if (single) { 00588 ast_indicate(in, -1); 00589 } 00590 } 00591 }
| static int do_timelimit | ( | struct ast_channel * | chan, | |
| struct ast_bridge_config * | config, | |||
| char * | parse, | |||
| struct timeval * | calldurationlimit | |||
| ) | [static] |
Definition at line 947 of file app_dial.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 dial_exec_full().
00949 { 00950 char *stringp = ast_strdupa(parse); 00951 char *limit_str, *warning_str, *warnfreq_str; 00952 const char *var; 00953 int play_to_caller = 0, play_to_callee = 0; 00954 int delta; 00955 00956 limit_str = strsep(&stringp, ":"); 00957 warning_str = strsep(&stringp, ":"); 00958 warnfreq_str = strsep(&stringp, ":"); 00959 00960 config->timelimit = atol(limit_str); 00961 if (warning_str) 00962 config->play_warning = atol(warning_str); 00963 if (warnfreq_str) 00964 config->warning_freq = atol(warnfreq_str); 00965 00966 if (!config->timelimit) { 00967 ast_log(LOG_WARNING, "Dial does not accept L(%s), hanging up.\n", limit_str); 00968 config->timelimit = config->play_warning = config->warning_freq = 0; 00969 config->warning_sound = NULL; 00970 return -1; /* error */ 00971 } else if ( (delta = config->play_warning - config->timelimit) > 0) { 00972 int w = config->warning_freq; 00973 00974 /* If the first warning is requested _after_ the entire call would end, 00975 and no warning frequency is requested, then turn off the warning. If 00976 a warning frequency is requested, reduce the 'first warning' time by 00977 that frequency until it falls within the call's total time limit. 00978 Graphically: 00979 timelim->| delta |<-playwarning 00980 0__________________|_________________| 00981 | w | | | | 00982 00983 so the number of intervals to cut is 1+(delta-1)/w 00984 */ 00985 00986 if (w == 0) { 00987 config->play_warning = 0; 00988 } else { 00989 config->play_warning -= w * ( 1 + (delta-1)/w ); 00990 if (config->play_warning < 1) 00991 config->play_warning = config->warning_freq = 0; 00992 } 00993 } 00994 00995 ast_channel_lock(chan); 00996 00997 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER"); 00998 00999 play_to_caller = var ? ast_true(var) : 1; 01000 01001 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE"); 01002 play_to_callee = var ? ast_true(var) : 0; 01003 01004 if (!play_to_caller && !play_to_callee) 01005 play_to_caller = 1; 01006 01007 var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE"); 01008 config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft"); 01009 01010 /* The code looking at config wants a NULL, not just "", to decide 01011 * that the message should not be played, so we replace "" with NULL. 01012 * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is 01013 * not found. 01014 */ 01015 01016 var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE"); 01017 config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 01018 01019 var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE"); 01020 config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL; 01021 01022 ast_channel_unlock(chan); 01023 01024 /* undo effect of S(x) in case they are both used */ 01025 calldurationlimit->tv_sec = 0; 01026 calldurationlimit->tv_usec = 0; 01027 01028 /* more efficient to do it like S(x) does since no advanced opts */ 01029 if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) { 01030 calldurationlimit->tv_sec = config->timelimit / 1000; 01031 calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000; 01032 ast_verb(3, "Setting call duration limit to %.3lf seconds.\n", 01033 calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0); 01034 config->timelimit = play_to_caller = play_to_callee = 01035 config->play_warning = config->warning_freq = 0; 01036 } else { 01037 ast_verb(3, "Limit Data for this call:\n"); 01038 ast_verb(4, "timelimit = %ld\n", config->timelimit); 01039 ast_verb(4, "play_warning = %ld\n", config->play_warning); 01040 ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no"); 01041 ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no"); 01042 ast_verb(4, "warning_freq = %ld\n", config->warning_freq); 01043 ast_verb(4, "start_sound = %s\n", S_OR(config->start_sound, "")); 01044 ast_verb(4, "warning_sound = %s\n", config->warning_sound); 01045 ast_verb(4, "end_sound = %s\n", S_OR(config->end_sound, "")); 01046 } 01047 if (play_to_caller) 01048 ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 01049 if (play_to_callee) 01050 ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 01051 return 0; 01052 }
| static void end_bridge_callback | ( | void * | data | ) | [static] |
Definition at line 1290 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().
01291 { 01292 char buf[80]; 01293 time_t end; 01294 struct ast_channel *chan = data; 01295 01296 if (!chan->cdr) { 01297 return; 01298 } 01299 01300 time(&end); 01301 01302 ast_channel_lock(chan); 01303 if (chan->cdr->answer.tv_sec) { 01304 snprintf(buf, sizeof(buf), "%ld", end - chan->cdr->answer.tv_sec); 01305 pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf); 01306 } 01307 01308 if (chan->cdr->start.tv_sec) { 01309 snprintf(buf, sizeof(buf), "%ld", end - chan->cdr->start.tv_sec); 01310 pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf); 01311 } 01312 ast_channel_unlock(chan); 01313 }
| static void end_bridge_callback_data_fixup | ( | struct ast_bridge_config * | bconfig, | |
| struct ast_channel * | originator, | |||
| struct ast_channel * | terminator | |||
| ) | [static] |
Definition at line 1315 of file app_dial.c.
References ast_bridge_config::end_bridge_callback_data.
Referenced by dial_exec_full().
01315 { 01316 bconfig->end_bridge_callback_data = originator; 01317 }
| static const char* get_cid_name | ( | char * | name, | |
| int | namelen, | |||
| struct ast_channel * | chan | |||
| ) | [static] |
Definition at line 456 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().
00457 { 00458 const char *context = S_OR(chan->macrocontext, chan->context); 00459 const char *exten = S_OR(chan->macroexten, chan->exten); 00460 00461 return ast_get_hint(NULL, 0, name, namelen, chan, context, exten) ? name : ""; 00462 }
| static void handle_cause | ( | int | cause, | |
| struct cause_args * | num | |||
| ) | [static] |
Definition at line 391 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().
00392 { 00393 struct ast_cdr *cdr = num->chan->cdr; 00394 00395 switch(cause) { 00396 case AST_CAUSE_BUSY: 00397 if (cdr) 00398 ast_cdr_busy(cdr); 00399 num->busy++; 00400 break; 00401 00402 case AST_CAUSE_CONGESTION: 00403 if (cdr) 00404 ast_cdr_failed(cdr); 00405 num->congestion++; 00406 break; 00407 00408 case AST_CAUSE_NO_ROUTE_DESTINATION: 00409 case AST_CAUSE_UNREGISTERED: 00410 if (cdr) 00411 ast_cdr_failed(cdr); 00412 num->nochan++; 00413 break; 00414 00415 case AST_CAUSE_NO_ANSWER: 00416 if (cdr) { 00417 ast_cdr_noanswer(cdr); 00418 } 00419 break; 00420 case AST_CAUSE_NORMAL_CLEARING: 00421 break; 00422 00423 default: 00424 num->nochan++; 00425 break; 00426 } 00427 }
| static void hanguptree | ( | struct chanlist * | outgoing, | |
| struct ast_channel * | exception, | |||
| int | answered_elsewhere | |||
| ) | [static] |
Definition at line 362 of file app_dial.c.
References AST_FLAG_ANSWERED_ELSEWHERE, ast_free, ast_hangup(), ast_set_flag, chanlist::chan, and chanlist::next.
Referenced by dial_exec_full().
00363 { 00364 /* Hang up a tree of stuff */ 00365 struct chanlist *oo; 00366 while (outgoing) { 00367 /* Hangup any existing lines we have open */ 00368 if (outgoing->chan && (outgoing->chan != exception)) { 00369 if (answered_elsewhere) 00370 ast_set_flag(outgoing->chan, AST_FLAG_ANSWERED_ELSEWHERE); 00371 ast_hangup(outgoing->chan); 00372 } 00373 oo = outgoing; 00374 outgoing = outgoing->next; 00375 ast_free(oo); 00376 } 00377 }
| static int load_module | ( | void | ) | [static] |
Definition at line 2267 of file app_dial.c.
References ast_add_extension2(), ast_context_find_or_create(), ast_free_ptr(), ast_log(), ast_register_application, ast_strdup, dial_exec(), LOG_ERROR, and retrydial_exec().
02268 { 02269 int res; 02270 struct ast_context *con; 02271 02272 con = ast_context_find_or_create(NULL, NULL, "app_dial_gosub_virtual_context", "app_dial"); 02273 if (!con) 02274 ast_log(LOG_ERROR, "Dial virtual context 'app_dial_gosub_virtual_context' does not exist and unable to create\n"); 02275 else 02276 ast_add_extension2(con, 1, "s", 1, NULL, NULL, "NoOp", ast_strdup(""), ast_free_ptr, "app_dial"); 02277 02278 res = ast_register_application(app, dial_exec, synopsis, descrip); 02279 res |= ast_register_application(rapp, retrydial_exec, rsynopsis, rdescrip); 02280 02281 return res; 02282 }
| static int onedigit_goto | ( | struct ast_channel * | chan, | |
| const char * | context, | |||
| char | exten, | |||
| int | pri | |||
| ) | [static] |
Definition at line 437 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().
00438 { 00439 char rexten[2] = { exten, '\0' }; 00440 00441 if (context) { 00442 if (!ast_goto_if_exists(chan, context, rexten, pri)) 00443 return 1; 00444 } else { 00445 if (!ast_goto_if_exists(chan, chan->context, rexten, pri)) 00446 return 1; 00447 else if (!ast_strlen_zero(chan->macrocontext)) { 00448 if (!ast_goto_if_exists(chan, chan->macrocontext, rexten, pri)) 00449 return 1; 00450 } 00451 } 00452 return 0; 00453 }
| static void replace_macro_delimiter | ( | char * | s | ) | [static] |
Definition at line 928 of file app_dial.c.
Referenced by dial_exec_full().
| static int retrydial_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 2143 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_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_test_flag64, ast_waitfordigit(), ast_waitstream(), context, ast_channel::data, dial_exec_full(), LOG_ERROR, LOG_WARNING, onedigit_goto(), OPT_DTMF_EXIT, parse(), and pbx_builtin_getvar_helper().
Referenced by load_module().
02144 { 02145 char *parse; 02146 const char *context = NULL; 02147 int sleepms = 0, loops = 0, res = -1; 02148 struct ast_flags64 peerflags = { 0, }; 02149 AST_DECLARE_APP_ARGS(args, 02150 AST_APP_ARG(announce); 02151 AST_APP_ARG(sleep); 02152 AST_APP_ARG(retries); 02153 AST_APP_ARG(dialdata); 02154 ); 02155 02156 if (ast_strlen_zero(data)) { 02157 ast_log(LOG_WARNING, "RetryDial requires an argument!\n"); 02158 return -1; 02159 } 02160 02161 parse = ast_strdupa(data); 02162 AST_STANDARD_APP_ARGS(args, parse); 02163 02164 if (!ast_strlen_zero(args.sleep) && (sleepms = atoi(args.sleep))) 02165 sleepms *= 1000; 02166 02167 if (!ast_strlen_zero(args.retries)) { 02168 loops = atoi(args.retries); 02169 } 02170 02171 if (!args.dialdata) { 02172 ast_log(LOG_ERROR, "%s requires a 4th argument (dialdata)\n", rapp); 02173 goto done; 02174 } 02175 02176 if (sleepms < 1000) 02177 sleepms = 10000; 02178 02179 if (!loops) 02180 loops = -1; /* run forever */ 02181 02182 ast_channel_lock(chan); 02183 context = pbx_builtin_getvar_helper(chan, "EXITCONTEXT"); 02184 context = !ast_strlen_zero(context) ? ast_strdupa(context) : NULL; 02185 ast_channel_unlock(chan); 02186 02187 res = 0; 02188 while (loops) { 02189 int continue_exec; 02190 02191 chan->data = "Retrying"; 02192 if (ast_test_flag(chan, AST_FLAG_MOH)) 02193 ast_moh_stop(chan); 02194 02195 res = dial_exec_full(chan, args.dialdata, &peerflags, &continue_exec); 02196 if (continue_exec) 02197 break; 02198 02199 if (res == 0) { 02200 if (ast_test_flag64(&peerflags, OPT_DTMF_EXIT)) { 02201 if (!ast_strlen_zero(args.announce)) { 02202 if (ast_fileexists(args.announce, NULL, chan->language) > 0) { 02203 if (!(res = ast_streamfile(chan, args.announce, chan->language))) 02204 ast_waitstream(chan, AST_DIGIT_ANY); 02205 } else 02206 ast_log(LOG_WARNING, "Announce file \"%s\" specified in Retrydial does not exist\n", args.announce); 02207 } 02208 if (!res && sleepms) { 02209 if (!ast_test_flag(chan, AST_FLAG_MOH)) 02210 ast_moh_start(chan, NULL, NULL); 02211 res = ast_waitfordigit(chan, sleepms); 02212 } 02213 } else { 02214 if (!ast_strlen_zero(args.announce)) { 02215 if (ast_fileexists(args.announce, NULL, chan->language) > 0) { 02216 if (!(res = ast_streamfile(chan, args.announce, chan->language))) 02217 res = ast_waitstream(chan, ""); 02218 } else 02219 ast_log(LOG_WARNING, "Announce file \"%s\" specified in Retrydial does not exist\n", args.announce); 02220 } 02221 if (sleepms) { 02222 if (!ast_test_flag(chan, AST_FLAG_MOH)) 02223 ast_moh_start(chan, NULL, NULL); 02224 if (!res) 02225 res = ast_waitfordigit(chan, sleepms); 02226 } 02227 } 02228 } 02229 02230 if (res < 0 || res == AST_PBX_INCOMPLETE) { 02231 break; 02232 } else if (res > 0) { /* Trying to send the call elsewhere (1 digit ext) */ 02233 if (onedigit_goto(chan, context, (char) res, 1)) { 02234 res = 0; 02235 break; 02236 } 02237 } 02238 loops--; 02239 } 02240 if (loops == 0) 02241 res = 0; 02242 else if (res == 1) 02243 res = 0; 02244 02245 if (ast_test_flag(chan, AST_FLAG_MOH)) 02246 ast_moh_stop(chan); 02247 done: 02248 return res; 02249 }
| static void senddialendevent | ( | const struct ast_channel * | src, | |
| const char * | dialstatus | |||
| ) | [static] |
Definition at line 480 of file app_dial.c.
References EVENT_FLAG_CALL, and manager_event.
Referenced by dial_exec_full().
00481 { 00482 manager_event(EVENT_FLAG_CALL, "Dial", 00483 "SubEvent: End\r\n" 00484 "Channel: %s\r\n" 00485 "UniqueID: %s\r\n" 00486 "DialStatus: %s\r\n", 00487 src->name, src->uniqueid, dialstatus); 00488 }
| static void senddialevent | ( | struct ast_channel * | src, | |
| struct ast_channel * | dst, | |||
| const char * | dialstring | |||
| ) | [static] |
Definition at line 464 of file app_dial.c.
References ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, EVENT_FLAG_CALL, manager_event, and S_OR.
Referenced by dial_exec_full(), and do_forward().
00465 { 00466 manager_event(EVENT_FLAG_CALL, "Dial", 00467 "SubEvent: Begin\r\n" 00468 "Channel: %s\r\n" 00469 "Destination: %s\r\n" 00470 "CallerIDNum: %s\r\n" 00471 "CallerIDName: %s\r\n" 00472 "UniqueID: %s\r\n" 00473 "DestUniqueID: %s\r\n" 00474 "Dialstring: %s\r\n", 00475 src->name, dst->name, S_OR(src->cid.cid_num, "<unknown>"), 00476 S_OR(src->cid.cid_name, "<unknown>"), src->uniqueid, 00477 dst->uniqueid, dialstring ? dialstring : ""); 00478 }
| 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 1189 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_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag64, ast_verb, ast_waitstream(), ast_channel::cid, ast_callerid::cid_num, ast_channel::exten, LOG_NOTICE, LOG_WARNING, 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().
01191 { 01192 char callerid[60]; 01193 int res; 01194 char *l; 01195 int silencethreshold; 01196 01197 if (!ast_strlen_zero(chan->cid.cid_num)) { 01198 l = ast_strdupa(chan->cid.cid_num); 01199 ast_shrink_phone_number(l); 01200 if (ast_test_flag64(opts, OPT_PRIVACY) ) { 01201 ast_verb(3, "Privacy DB is '%s', clid is '%s'\n", opt_args[OPT_ARG_PRIVACY], l); 01202 pa->privdb_val = ast_privacy_check(opt_args[OPT_ARG_PRIVACY], l); 01203 } else { 01204 ast_verb(3, "Privacy Screening, clid is '%s'\n", l); 01205 pa->privdb_val = AST_PRIVACY_UNKNOWN; 01206 } 01207 } else { 01208 char *tnam, *tn2; 01209 01210 tnam = ast_strdupa(chan->name); 01211 /* clean the channel name so slashes don't try to end up in disk file name */ 01212 for (tn2 = tnam; *tn2; tn2++) { 01213 if (*tn2 == '/') /* any other chars to be afraid of? */ 01214 *tn2 = '='; 01215 } 01216 ast_verb(3, "Privacy-- callerid is empty\n"); 01217 01218 snprintf(callerid, sizeof(callerid), "NOCALLERID_%s%s", chan->exten, tnam); 01219 l = callerid; 01220 pa->privdb_val = AST_PRIVACY_UNKNOWN; 01221 } 01222 01223 ast_copy_string(pa->privcid, l, sizeof(pa->privcid)); 01224 01225 if (strncmp(pa->privcid, "NOCALLERID", 10) != 0 && ast_test_flag64(opts, OPT_SCREEN_NOCLID)) { 01226 /* if callerid is set and OPT_SCREEN_NOCLID is set also */ 01227 ast_verb(3, "CallerID set (%s); N option set; Screening should be off\n", pa->privcid); 01228 pa->privdb_val = AST_PRIVACY_ALLOW; 01229 } else if (ast_test_flag64(opts, OPT_SCREEN_NOCLID) && strncmp(pa->privcid, "NOCALLERID", 10) == 0) { 01230 ast_verb(3, "CallerID blank; N option set; Screening should happen; dbval is %d\n", pa->privdb_val); 01231 } 01232 01233 if (pa->privdb_val == AST_PRIVACY_DENY) { 01234 ast_verb(3, "Privacy DB reports PRIVACY_DENY for this callerid. Dial reports unavailable\n"); 01235 ast_copy_string(pa->status, "NOANSWER", sizeof(pa->status)); 01236 return 0; 01237 } else if (pa->privdb_val == AST_PRIVACY_KILL) { 01238 ast_copy_string(pa->status, "DONTCALL", sizeof(pa->status)); 01239 return 0; /* Is this right? */ 01240 } else if (pa->privdb_val == AST_PRIVACY_TORTURE) { 01241 ast_copy_string(pa->status, "TORTURE", sizeof(pa->status)); 01242 return 0; /* is this right??? */ 01243 } else if (pa->privdb_val == AST_PRIVACY_UNKNOWN) { 01244 /* Get the user's intro, store it in priv-callerintros/$CID, 01245 unless it is already there-- this should be done before the 01246 call is actually dialed */ 01247 01248 /* make sure the priv-callerintros dir actually exists */ 01249 snprintf(pa->privintro, sizeof(pa->privintro), "%s/sounds/priv-callerintros", ast_config_AST_DATA_DIR); 01250 if ((res = ast_mkdir(pa->privintro, 0755))) { 01251 ast_log(LOG_WARNING, "privacy: can't create directory priv-callerintros: %s\n", strerror(res)); 01252 return -1; 01253 } 01254 01255 snprintf(pa->privintro, sizeof(pa->privintro), "priv-callerintros/%s", pa->privcid); 01256 if (ast_fileexists(pa->privintro, NULL, NULL ) > 0 && strncmp(pa->privcid, "NOCALLERID", 10) != 0) { 01257 /* the DELUX version of this code would allow this caller the 01258 option to hear and retape their previously recorded intro. 01259 */ 01260 } else { 01261 int duration; /* for feedback from play_and_wait */ 01262 /* the file doesn't exist yet. Let the caller submit his 01263 vocal intro for posterity */ 01264 /* priv-recordintro script: 01265 01266 "At the tone, please say your name:" 01267 01268 */ 01269 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE); 01270 ast_answer(chan); 01271 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 */ 01272 /* don't think we'll need a lock removed, we took care of 01273 conflicts by naming the pa.privintro file */ 01274 if (res == -1) { 01275 /* Delete the file regardless since they hung up during recording */ 01276 ast_filedelete(pa->privintro, NULL); 01277 if (ast_fileexists(pa->privintro, NULL, NULL) > 0) 01278 ast_log(LOG_NOTICE, "privacy: ast_filedelete didn't do its job on %s\n", pa->privintro); 01279 else 01280 ast_verb(3, "Successfully deleted %s intro file\n", pa->privintro); 01281 return -1; 01282 } 01283 if (!ast_streamfile(chan, "vm-dialout", chan->language) ) 01284 ast_waitstream(chan, ""); 01285 } 01286 } 01287 return 1; /* success */ 01288 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 2251 of file app_dial.c.
References ast_context_destroy(), ast_context_find(), ast_context_remove_extension2(), and ast_unregister_application().
02252 { 02253 int res; 02254 struct ast_context *con; 02255 02256 res = ast_unregister_application(app); 02257 res |= ast_unregister_application(rapp); 02258 02259 if ((con = ast_context_find("app_dial_gosub_virtual_context"))) { 02260 ast_context_remove_extension2(con, "s", 1, NULL, 0); 02261 ast_context_destroy(con, "app_dial"); /* leave nothing behind */ 02262 } 02263 02264 return res; 02265 }
| static int valid_priv_reply | ( | struct ast_flags64 * | opts, | |
| int | res | |||
| ) | [static] |
Definition at line 936 of file app_dial.c.
References ast_test_flag64, OPT_PRIVACY, and OPT_SCREENING.
00937 { 00938 if (res < '1') 00939 return 0; 00940 if (ast_test_flag64(opts, OPT_PRIVACY) && res <= '5') 00941 return 1; 00942 if (ast_test_flag64(opts, OPT_SCREENING) && res <= '4') 00943 return 1; 00944 return 0; 00945 }
| 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 602 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_str_alloca, ast_string_field_set, ast_strlen_zero(), ast_test_flag64, ast_tvnow(), ast_verb, ast_waitfor_n(), ast_write(), cause_args::busy, CAN_EARLY_BRIDGE, ast_channel::cdr, chanlist::chan, cause_args::congestion, context, ast_frame::data, ast_frame::datalen, detect_disconnect(), DIAL_NOFORWARDHTML, DIAL_STILLGOING, dialcontext, ast_cdr::disposition, do_forward(), ast_channel::exten, f, FEATURE_MAX_LEN, ast_frame::frametype, handle_cause(), ast_channel::hangupcause, LOG_WARNING, 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().
00606 { 00607 struct cause_args num = *num_in; 00608 int prestart = num.busy + num.congestion + num.nochan; 00609 int orig = *to; 00610 struct ast_channel *peer = NULL; 00611 /* single is set if only one destination is enabled */ 00612 int single = outgoing && !outgoing->next && !ast_test_flag64(outgoing, OPT_MUSICBACK | OPT_RINGBACK); 00613 #ifdef HAVE_EPOLL 00614 struct chanlist *epollo; 00615 #endif 00616 struct ast_str *featurecode = ast_str_alloca(FEATURE_MAX_LEN + 1); 00617 if (single) { 00618 /* Turn off hold music, etc */ 00619 ast_deactivate_generator(in); 00620 /* If we are calling a single channel, make them compatible for in-band tone purpose */ 00621 ast_channel_make_compatible(outgoing->chan, in); 00622 } 00623 00624 #ifdef HAVE_EPOLL 00625 for (epollo = outgoing; epollo; epollo = epollo->next) 00626 ast_poll_channel_add(in, epollo->chan); 00627 #endif 00628 00629 while (*to && !peer) { 00630 struct chanlist *o; 00631 int pos = 0; /* how many channels do we handle */ 00632 int numlines = prestart; 00633 struct ast_channel *winner; 00634 struct ast_channel *watchers[AST_MAX_WATCHERS]; 00635 00636 watchers[pos++] = in; 00637 for (o = outgoing; o; o = o->next) { 00638 /* Keep track of important channels */ 00639 if (ast_test_flag64(o, DIAL_STILLGOING) && o->chan) 00640 watchers[pos++] = o->chan; 00641 numlines++; 00642 } 00643 if (pos == 1) { /* only the input channel is available */ 00644 if (numlines == (num.busy + num.congestion + num.nochan)) { 00645 ast_verb(2, "Everyone is busy/congested at this time (%d:%d/%d/%d)\n", numlines, num.busy, num.congestion, num.nochan); 00646 if (num.busy) 00647 strcpy(pa->status, "BUSY"); 00648 else if (num.congestion) 00649 strcpy(pa->status, "CONGESTION"); 00650 else if (num.nochan) 00651 strcpy(pa->status, "CHANUNAVAIL"); 00652 } else { 00653 ast_verb(3, "No one is available to answer at this time (%d:%d/%d/%d)\n", numlines, num.busy, num.congestion, num.nochan); 00654 } 00655 *to = 0; 00656 return NULL; 00657 } 00658 winner = ast_waitfor_n(watchers, pos, to); 00659 for (o = outgoing; o; o = o->next) { 00660 struct ast_frame *f; 00661 struct ast_channel *c = o->chan; 00662 00663 if (c == NULL) 00664 continue; 00665 if (ast_test_flag64(o, DIAL_STILLGOING) && c->_state == AST_STATE_UP) { 00666 if (!peer) { 00667 ast_verb(3, "%s answered %s\n", c->name, in->name); 00668 peer = c; 00669 ast_copy_flags64(peerflags, o, 00670 OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER | 00671 OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP | 00672 OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR | 00673 OPT_CALLEE_PARK | OPT_CALLER_PARK | 00674 OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR | 00675 DIAL_NOFORWARDHTML); 00676 ast_string_field_set(c, dialcontext, ""); 00677 ast_copy_string(c->exten, "", sizeof(c->exten)); 00678 } 00679 continue; 00680 } 00681 if (c != winner) 00682 continue; 00683 /* here, o->chan == c == winner */ 00684 if (!ast_strlen_zero(c->call_forward)) { 00685 do_forward(o, &num, peerflags, single); 00686 continue; 00687 } 00688 f = ast_read(winner); 00689 if (!f) { 00690 in->hangupcause = c->hangupcause; 00691 #ifdef HAVE_EPOLL 00692 ast_poll_channel_del(in, c); 00693 #endif 00694 ast_hangup(c); 00695 c = o->chan = NULL; 00696 ast_clear_flag64(o, DIAL_STILLGOING); 00697 handle_cause(in->hangupcause, &num); 00698 continue; 00699 } 00700 if (f->frametype == AST_FRAME_CONTROL) { 00701 switch(f->subclass) { 00702 case AST_CONTROL_ANSWER: 00703 /* This is our guy if someone answered. */ 00704 if (!peer) { 00705 ast_verb(3, "%s answered %s\n", c->name, in->name); 00706 peer = c; 00707 if (peer->cdr) { 00708 peer->cdr->answer = ast_tvnow(); 00709 peer->cdr->disposition = AST_CDR_ANSWERED; 00710 } 00711 ast_copy_flags64(peerflags, o, 00712 OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER | 00713 OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP | 00714 OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR | 00715 OPT_CALLEE_PARK | OPT_CALLER_PARK | 00716 OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR | 00717 DIAL_NOFORWARDHTML); 00718 ast_string_field_set(c, dialcontext, ""); 00719 ast_copy_string(c->exten, "", sizeof(c->exten)); 00720 if (CAN_EARLY_BRIDGE(peerflags, in, peer)) 00721 /* Setup early bridge if appropriate */ 00722 ast_channel_early_bridge(in, peer); 00723 } 00724 /* If call has been answered, then the eventual hangup is likely to be normal hangup */ 00725 in->hangupcause = AST_CAUSE_NORMAL_CLEARING; 00726 c->hangupcause = AST_CAUSE_NORMAL_CLEARING; 00727 break; 00728 case AST_CONTROL_BUSY: 00729 ast_verb(3, "%s is busy\n", c->name); 00730 in->hangupcause = c->hangupcause; 00731 ast_hangup(c); 00732 c = o->chan = NULL; 00733 ast_clear_flag64(o, DIAL_STILLGOING); 00734 handle_cause(AST_CAUSE_BUSY, &num); 00735 break; 00736 case AST_CONTROL_CONGESTION: 00737 ast_verb(3, "%s is circuit-busy\n", c->name); 00738 in->hangupcause = c->hangupcause; 00739 ast_hangup(c); 00740 c = o->chan = NULL; 00741 ast_clear_flag64(o, DIAL_STILLGOING); 00742 handle_cause(AST_CAUSE_CONGESTION, &num); 00743 break; 00744 case AST_CONTROL_RINGING: 00745 ast_verb(3, "%s is ringing\n", c->name); 00746 /* Setup early media if appropriate */ 00747 if (single && CAN_EARLY_BRIDGE(peerflags, in, c)) 00748 ast_channel_early_bridge(in, c); 00749 if (!(pa->sentringing) && !ast_test_flag64(outgoing, OPT_MUSICBACK)) { 00750 ast_indicate(in, AST_CONTROL_RINGING); 00751 pa->sentringing++; 00752 } 00753 break; 00754 case AST_CONTROL_PROGRESS: 00755 ast_verb(3, "%s is making progress passing it to %s\n", c->name, in->name); 00756 /* Setup early media if appropriate */ 00757 if (single && CAN_EARLY_BRIDGE(peerflags, in, c)) 00758 ast_channel_early_bridge(in, c); 00759 if (!ast_test_flag64(outgoing, OPT_RINGBACK)) 00760 if (single || (!single && !pa->sentringing)) { 00761 ast_indicate(in, AST_CONTROL_PROGRESS); 00762 } 00763 break; 00764 case AST_CONTROL_VIDUPDATE: 00765 ast_verb(3, "%s requested a video update, passing it to %s\n", c->name, in->name); 00766 ast_indicate(in, AST_CONTROL_VIDUPDATE); 00767 break; 00768 case AST_CONTROL_SRCUPDATE: 00769 ast_verb(3, "%s requested a source update, passing it to %s\n", c->name, in->name); 00770 ast_indicate(in, AST_CONTROL_SRCUPDATE); 00771 break; 00772 case AST_CONTROL_PROCEEDING: 00773 ast_verb(3, "%s is proceeding passing it to %s\n", c->name, in->name); 00774 if (single && CAN_EARLY_BRIDGE(peerflags, in, c)) 00775 ast_channel_early_bridge(in, c); 00776 if (!ast_test_flag64(outgoing, OPT_RINGBACK)) 00777 ast_indicate(in, AST_CONTROL_PROCEEDING); 00778 break; 00779 case AST_CONTROL_HOLD: 00780 ast_verb(3, "Call on %s placed on hold\n", c->name); 00781 ast_indicate(in, AST_CONTROL_HOLD); 00782 break; 00783 case AST_CONTROL_UNHOLD: 00784 ast_verb(3, "Call on %s left from hold\n", c->name); 00785 ast_indicate(in, AST_CONTROL_UNHOLD); 00786 break; 00787 case AST_CONTROL_OFFHOOK: 00788 case AST_CONTROL_FLASH: 00789 /* Ignore going off hook and flash */ 00790 break; 00791 case -1: 00792 if (!ast_test_flag64(outgoing, OPT_RINGBACK | OPT_MUSICBACK)) { 00793 ast_verb(3, "%s stopped sounds\n", c->name); 00794 ast_indicate(in, -1); 00795 pa->sentringing = 0; 00796 } 00797 break; 00798 default: 00799 ast_debug(1, "Dunno what to do with control type %d\n", f->subclass); 00800 } 00801 } else if (single) { 00802 switch (f->frametype) { 00803 case AST_FRAME_VOICE: 00804 case AST_FRAME_IMAGE: 00805 case AST_FRAME_TEXT: 00806 if (ast_write(in, f)) { 00807 ast_log(LOG_WARNING, "Unable to write frame\n"); 00808 } 00809 break; 00810 case AST_FRAME_HTML: 00811 if (!ast_test_flag64(outgoing, DIAL_NOFORWARDHTML) && ast_channel_sendhtml(in, f->subclass, f->data.ptr, f->datalen) == -1) { 00812 ast_log(LOG_WARNING, "Unable to send URL\n"); 00813 } 00814 break; 00815 default: 00816 break; 00817 } 00818 } 00819 ast_frfree(f); 00820 } /* end for */ 00821 if (winner == in) { 00822 struct ast_frame *f = ast_read(in); 00823 #if 0 00824 if (f && (f->frametype != AST_FRAME_VOICE)) 00825 printf("Frame type: %d, %d\n", f->frametype, f->subclass); 00826 else if (!f || (f->frametype != AST_FRAME_VOICE)) 00827 printf("Hangup received on %s\n", in->name); 00828 #endif 00829 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) { 00830 /* Got hung up */ 00831 *to = -1; 00832 strcpy(pa->status, "CANCEL"); 00833 ast_cdr_noanswer(in->cdr); 00834 if (f) { 00835 if (f->data.uint32) { 00836 in->hangupcause = f->data.uint32; 00837 } 00838 ast_frfree(f); 00839 } 00840 return NULL; 00841 } 00842 00843 /* now f is guaranteed non-NULL */ 00844 if (f->frametype == AST_FRAME_DTMF) { 00845 if (ast_test_flag64(peerflags, OPT_DTMF_EXIT)) { 00846 const char *context; 00847 ast_channel_lock(in); 00848 context = pbx_builtin_getvar_helper(in, "EXITCONTEXT"); 00849 if (onedigit_goto(in, context, (char) f->subclass, 1)) { 00850 ast_verb(3, "User hit %c to disconnect call.\n", f->subclass); 00851 *to = 0; 00852 ast_cdr_noanswer(in->cdr); 00853 *result = f->subclass; 00854 strcpy(pa->status, "CANCEL"); 00855 ast_frfree(f); 00856 ast_channel_unlock(in); 00857 return NULL; 00858 } 00859 ast_channel_unlock(in); 00860 } 00861 00862 if (ast_test_flag64(peerflags, OPT_CALLER_HANGUP) && 00863 detect_disconnect(in, f->subclass, featurecode)) { 00864 ast_verb(3, "User requested call disconnect.\n"); 00865 *to = 0; 00866 strcpy(pa->status, "CANCEL"); 00867 ast_cdr_noanswer(in->cdr); 00868 ast_frfree(f); 00869 return NULL; 00870 } 00871 } 00872 00873 /* Forward HTML stuff */ 00874 if (single && (f->frametype == AST_FRAME_HTML) && !ast_test_flag64(outgoing, DIAL_NOFORWARDHTML)) 00875 if (ast_channel_sendhtml(outgoing->chan, f->subclass, f->data.ptr, f->datalen) == -1) 00876 ast_log(LOG_WARNING, "Unable to send URL\n"); 00877 00878 if (single && ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_DTMF_BEGIN) || (f->frametype == AST_FRAME_DTMF_END))) { 00879 if (ast_write(outgoing->chan, f)) 00880 ast_log(LOG_WARNING, "Unable to forward voice or dtmf\n"); 00881 } 00882 if (single && (f->frametype == AST_FRAME_CONTROL) && 00883 ((f->subclass == AST_CONTROL_HOLD) || 00884 (f->subclass == AST_CONTROL_UNHOLD) || 00885 (f->subclass == AST_CONTROL_VIDUPDATE) || 00886 (f->subclass == AST_CONTROL_SRCUPDATE))) { 00887 ast_verb(3, "%s requested special control %d, passing it to %s\n", in->name, f->subclass, outgoing->chan->name); 00888 ast_indicate_data(outgoing->chan, f->subclass, f->data.ptr, f->datalen); 00889 } 00890 ast_frfree(f); 00891 } 00892 if (!*to) 00893 ast_verb(3, "Nobody picked up in %d ms\n", orig); 00894 if (!*to || ast_check_hangup(in)) 00895 ast_cdr_noanswer(in->cdr); 00896 } 00897 00898 #ifdef HAVE_EPOLL 00899 for (epollo = outgoing; epollo; epollo = epollo->next) { 00900 if (epollo->chan) 00901 ast_poll_channel_del(in, epollo->chan); 00902 } 00903 #endif 00904 00905 return peer; 00906 }
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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, } [static] |
Definition at line 2284 of file app_dial.c.
char* app = "Dial" [static] |
Definition at line 65 of file app_dial.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 2284 of file app_dial.c.
char* descrip [static] |
Definition at line 69 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 343 of file app_dial.c.
Referenced by dial_exec_full().
char* rapp = "RetryDial" [static] |
Definition at line 238 of file app_dial.c.
char* rdescrip [static] |
Definition at line 240 of file app_dial.c.
char* rsynopsis = "Place a call, retrying on failure allowing optional exit extension." [static] |
Definition at line 239 of file app_dial.c.
char* synopsis = "Place a call and connect to the current channel" [static] |
Definition at line 67 of file app_dial.c.
1.6.1