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