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