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