#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"
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_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_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, unsigned int *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 = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, } |
static char * | app = "Dial" |
static const 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 }, [ '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 367 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 334 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 279 of file app_dial.c.
Referenced by dial_exec_full(), do_forward(), and wait_for_answer().
#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 246 of file app_dial.c.
00246 { 00247 OPT_ANNOUNCE = (1 << 0), 00248 OPT_RESETCDR = (1 << 1), 00249 OPT_DTMF_EXIT = (1 << 2), 00250 OPT_SENDDTMF = (1 << 3), 00251 OPT_FORCECLID = (1 << 4), 00252 OPT_GO_ON = (1 << 5), 00253 OPT_CALLEE_HANGUP = (1 << 6), 00254 OPT_CALLER_HANGUP = (1 << 7), 00255 OPT_DURATION_LIMIT = (1 << 9), 00256 OPT_MUSICBACK = (1 << 10), 00257 OPT_CALLEE_MACRO = (1 << 11), 00258 OPT_SCREEN_NOINTRO = (1 << 12), 00259 OPT_SCREEN_NOCLID = (1 << 13), 00260 OPT_ORIGINAL_CLID = (1 << 14), 00261 OPT_SCREENING = (1 << 15), 00262 OPT_PRIVACY = (1 << 16), 00263 OPT_RINGBACK = (1 << 17), 00264 OPT_DURATION_STOP = (1 << 18), 00265 OPT_CALLEE_TRANSFER = (1 << 19), 00266 OPT_CALLER_TRANSFER = (1 << 20), 00267 OPT_CALLEE_MONITOR = (1 << 21), 00268 OPT_CALLER_MONITOR = (1 << 22), 00269 OPT_GOTO = (1 << 23), 00270 OPT_OPERMODE = (1 << 24), 00271 OPT_CALLEE_PARK = (1 << 25), 00272 OPT_CALLER_PARK = (1 << 26), 00273 OPT_IGNORE_FORWARDING = (1 << 27), 00274 OPT_CALLEE_GOSUB = (1 << 28), 00275 OPT_CALLEE_MIXMONITOR = (1 << 29), 00276 OPT_CALLER_MIXMONITOR = (1 << 30), 00277 };
anonymous enum |
Definition at line 284 of file app_dial.c.
00284 { 00285 OPT_ARG_ANNOUNCE = 0, 00286 OPT_ARG_SENDDTMF, 00287 OPT_ARG_GOTO, 00288 OPT_ARG_DURATION_LIMIT, 00289 OPT_ARG_MUSICBACK, 00290 OPT_ARG_CALLEE_MACRO, 00291 OPT_ARG_CALLEE_GOSUB, 00292 OPT_ARG_PRIVACY, 00293 OPT_ARG_DURATION_STOP, 00294 OPT_ARG_OPERMODE, 00295 /* note: this entry _MUST_ be the last one in the enum */ 00296 OPT_ARG_ARRAY_SIZE, 00297 };
static void __reg_module | ( | void | ) | [static] |
Definition at line 2139 of file app_dial.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 2139 of file app_dial.c.
static int detect_disconnect | ( | struct ast_channel * | chan, | |
char | code, | |||
struct ast_str * | featurecode | |||
) | [static] |
Definition at line 879 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.
00880 { 00881 struct ast_flags features = { AST_FEATURE_DISCONNECT }; /* only concerned with disconnect feature */ 00882 struct ast_call_feature feature = { 0, }; 00883 int res; 00884 00885 ast_str_append(&featurecode, 1, "%c", code); 00886 00887 res = ast_feature_detect(chan, &features, ast_str_buffer(featurecode), &feature); 00888 00889 if (res != AST_FEATURE_RETURN_STOREDIGITS) { 00890 ast_str_reset(featurecode); 00891 } 00892 if (feature.feature_mask & AST_FEATURE_DISCONNECT) { 00893 return 1; 00894 } 00895 00896 return 0; 00897 }
static int dial_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 1992 of file app_dial.c.
References chan, and dial_exec_full().
Referenced by load_module().
01993 { 01994 struct ast_flags64 peerflags; 01995 01996 memset(&peerflags, 0, sizeof(peerflags)); 01997 01998 return dial_exec_full(chan, data, &peerflags, NULL); 01999 }
static int dial_exec_full | ( | struct ast_channel * | chan, | |
void * | data, | |||
struct ast_flags64 * | peerflags, | |||
int * | continue_exec | |||
) | [static] |
Definition at line 1283 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_cdr_reset(), ast_cdr_setdestchan(), ast_channel_datastore_add(), ast_channel_datastore_alloc(), ast_channel_datastore_find(), ast_channel_datastore_free(), 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_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_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_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, 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, 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_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_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().
01284 { 01285 int res = -1; /* default: error */ 01286 char *rest, *cur; /* scan the list of destinations */ 01287 struct chanlist *outgoing = NULL; /* list of destinations */ 01288 struct ast_channel *peer; 01289 int to; /* timeout */ 01290 struct cause_args num = { chan, 0, 0, 0 }; 01291 int cause; 01292 char numsubst[256]; 01293 char cidname[AST_MAX_EXTENSION] = ""; 01294 01295 struct ast_bridge_config config = { { 0, } }; 01296 unsigned int calldurationlimit = 0; 01297 char *dtmfcalled = NULL, *dtmfcalling = NULL; 01298 struct privacy_args pa = { 01299 .sentringing = 0, 01300 .privdb_val = 0, 01301 .status = "INVALIDARGS", 01302 }; 01303 int sentringing = 0, moh = 0; 01304 const char *outbound_group = NULL; 01305 int result = 0; 01306 char *parse; 01307 int opermode = 0; 01308 AST_DECLARE_APP_ARGS(args, 01309 AST_APP_ARG(peers); 01310 AST_APP_ARG(timeout); 01311 AST_APP_ARG(options); 01312 AST_APP_ARG(url); 01313 ); 01314 struct ast_flags64 opts = { 0, }; 01315 char *opt_args[OPT_ARG_ARRAY_SIZE]; 01316 struct ast_datastore *datastore = NULL; 01317 int fulldial = 0, num_dialed = 0; 01318 01319 /* Reset all DIAL variables back to blank, to prevent confusion (in case we don't reset all of them). */ 01320 pbx_builtin_setvar_helper(chan, "DIALSTATUS", ""); 01321 pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", ""); 01322 pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", ""); 01323 pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", ""); 01324 pbx_builtin_setvar_helper(chan, "DIALEDTIME", ""); 01325 01326 if (ast_strlen_zero(data)) { 01327 ast_log(LOG_WARNING, "Dial requires an argument (technology/number)\n"); 01328 pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status); 01329 return -1; 01330 } 01331 01332 parse = ast_strdupa(data); 01333 01334 AST_STANDARD_APP_ARGS(args, parse); 01335 01336 if (!ast_strlen_zero(args.options) && 01337 ast_app_parse_options64(dial_exec_options, &opts, opt_args, args.options)) { 01338 pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status); 01339 goto done; 01340 } 01341 01342 if (ast_strlen_zero(args.peers)) { 01343 ast_log(LOG_WARNING, "Dial requires an argument (technology/number)\n"); 01344 pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status); 01345 goto done; 01346 } 01347 01348 if (ast_test_flag64(&opts, OPT_OPERMODE)) { 01349 opermode = ast_strlen_zero(opt_args[OPT_ARG_OPERMODE]) ? 1 : atoi(opt_args[OPT_ARG_OPERMODE]); 01350 ast_verb(3, "Setting operator services mode to %d.\n", opermode); 01351 } 01352 01353 if (ast_test_flag64(&opts, OPT_DURATION_STOP) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_STOP])) { 01354 calldurationlimit = atoi(opt_args[OPT_ARG_DURATION_STOP]); 01355 if (!calldurationlimit) { 01356 ast_log(LOG_WARNING, "Dial does not accept S(%s), hanging up.\n", opt_args[OPT_ARG_DURATION_STOP]); 01357 pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status); 01358 goto done; 01359 } 01360 ast_verb(3, "Setting call duration limit to %d seconds.\n", calldurationlimit); 01361 } 01362 01363 if (ast_test_flag64(&opts, OPT_SENDDTMF) && !ast_strlen_zero(opt_args[OPT_ARG_SENDDTMF])) { 01364 dtmfcalling = opt_args[OPT_ARG_SENDDTMF]; 01365 dtmfcalled = strsep(&dtmfcalling, ":"); 01366 } 01367 01368 if (ast_test_flag64(&opts, OPT_DURATION_LIMIT) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])) { 01369 if (do_timelimit(chan, &config, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit)) 01370 goto done; 01371 } 01372 01373 if (ast_test_flag64(&opts, OPT_RESETCDR) && chan->cdr) 01374 ast_cdr_reset(chan->cdr, NULL); 01375 if (ast_test_flag64(&opts, OPT_PRIVACY) && ast_strlen_zero(opt_args[OPT_ARG_PRIVACY])) 01376 opt_args[OPT_ARG_PRIVACY] = ast_strdupa(chan->exten); 01377 01378 if (ast_test_flag64(&opts, OPT_PRIVACY) || ast_test_flag64(&opts, OPT_SCREENING)) { 01379 res = setup_privacy_args(&pa, &opts, opt_args, chan); 01380 if (res <= 0) 01381 goto out; 01382 res = -1; /* reset default */ 01383 } 01384 01385 if (ast_test_flag64(&opts, OPT_DTMF_EXIT) || ast_test_flag64(&opts, OPT_CALLER_HANGUP)) { 01386 __ast_answer(chan, 0, 0); 01387 } 01388 01389 if (continue_exec) 01390 *continue_exec = 0; 01391 01392 /* If a channel group has been specified, get it for use when we create peer channels */ 01393 if ((outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP_ONCE"))) { 01394 outbound_group = ast_strdupa(outbound_group); 01395 pbx_builtin_setvar_helper(chan, "OUTBOUND_GROUP_ONCE", NULL); 01396 } else { 01397 outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP"); 01398 } 01399 01400 ast_copy_flags64(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING); 01401 01402 /* loop through the list of dial destinations */ 01403 rest = args.peers; 01404 while ((cur = strsep(&rest, "&")) ) { 01405 struct chanlist *tmp; 01406 struct ast_channel *tc; /* channel for this destination */ 01407 /* Get a technology/[device:]number pair */ 01408 char *number = cur; 01409 char *interface = ast_strdupa(number); 01410 char *tech = strsep(&number, "/"); 01411 /* find if we already dialed this interface */ 01412 struct ast_dialed_interface *di; 01413 AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces; 01414 num_dialed++; 01415 if (!number) { 01416 ast_log(LOG_WARNING, "Dial argument takes format (technology/[device:]number1)\n"); 01417 goto out; 01418 } 01419 if (!(tmp = ast_calloc(1, sizeof(*tmp)))) 01420 goto out; 01421 if (opts.flags) { 01422 ast_copy_flags64(tmp, &opts, 01423 OPT_CANCEL_ELSEWHERE | 01424 OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER | 01425 OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP | 01426 OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR | 01427 OPT_CALLEE_PARK | OPT_CALLER_PARK | 01428 OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR | 01429 OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID); 01430 ast_set2_flag64(tmp, args.url, DIAL_NOFORWARDHTML); 01431 } 01432 ast_copy_string(numsubst, number, sizeof(numsubst)); 01433 /* Request the peer */ 01434 01435 ast_channel_lock(chan); 01436 datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL); 01437 ast_channel_unlock(chan); 01438 01439 if (datastore) 01440 dialed_interfaces = datastore->data; 01441 else { 01442 if (!(datastore = ast_channel_datastore_alloc(&dialed_interface_info, NULL))) { 01443 ast_log(LOG_WARNING, "Unable to create channel datastore for dialed interfaces. Aborting!\n"); 01444 ast_free(tmp); 01445 goto out; 01446 } 01447 01448 datastore->inheritance = DATASTORE_INHERIT_FOREVER; 01449 01450 if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) { 01451 ast_free(tmp); 01452 goto out; 01453 } 01454 01455 datastore->data = dialed_interfaces; 01456 AST_LIST_HEAD_INIT(dialed_interfaces); 01457 01458 ast_channel_lock(chan); 01459 ast_channel_datastore_add(chan, datastore); 01460 ast_channel_unlock(chan); 01461 } 01462 01463 AST_LIST_LOCK(dialed_interfaces); 01464 AST_LIST_TRAVERSE(dialed_interfaces, di, list) { 01465 if (!strcasecmp(di->interface, interface)) { 01466 ast_log(LOG_WARNING, "Skipping dialing interface '%s' again since it has already been dialed\n", 01467 di->interface); 01468 break; 01469 } 01470 } 01471 AST_LIST_UNLOCK(dialed_interfaces); 01472 01473 if (di) { 01474 fulldial++; 01475 ast_free(tmp); 01476 continue; 01477 } 01478 01479 /* It is always ok to dial a Local interface. We only keep track of 01480 * which "real" interfaces have been dialed. The Local channel will 01481 * inherit this list so that if it ends up dialing a real interface, 01482 * it won't call one that has already been called. */ 01483 if (strcasecmp(tech, "Local")) { 01484 if (!(di = ast_calloc(1, sizeof(*di) + strlen(interface)))) { 01485 AST_LIST_UNLOCK(dialed_interfaces); 01486 ast_free(tmp); 01487 goto out; 01488 } 01489 strcpy(di->interface, interface); 01490 01491 AST_LIST_LOCK(dialed_interfaces); 01492 AST_LIST_INSERT_TAIL(dialed_interfaces, di, list); 01493 AST_LIST_UNLOCK(dialed_interfaces); 01494 } 01495 01496 tc = ast_request(tech, chan->nativeformats, numsubst, &cause); 01497 if (!tc) { 01498 /* If we can't, just go on to the next call */ 01499 ast_log(LOG_WARNING, "Unable to create channel of type '%s' (cause %d - %s)\n", 01500 tech, cause, ast_cause2str(cause)); 01501 handle_cause(cause, &num); 01502 if (!rest) /* we are on the last destination */ 01503 chan->hangupcause = cause; 01504 ast_free(tmp); 01505 continue; 01506 } 01507 pbx_builtin_setvar_helper(tc, "DIALEDPEERNUMBER", numsubst); 01508 01509 /* Setup outgoing SDP to match incoming one */ 01510 ast_rtp_make_compatible(tc, chan, !outgoing && !rest); 01511 01512 /* Inherit specially named variables from parent channel */ 01513 ast_channel_inherit_variables(chan, tc); 01514 ast_channel_datastore_inherit(chan, tc); 01515 01516 tc->appl = "AppDial"; 01517 tc->data = "(Outgoing Line)"; 01518 tc->whentohangup = 0; 01519 01520 S_REPLACE(tc->cid.cid_num, ast_strdup(chan->cid.cid_num)); 01521 S_REPLACE(tc->cid.cid_name, ast_strdup(chan->cid.cid_name)); 01522 S_REPLACE(tc->cid.cid_ani, ast_strdup(chan->cid.cid_ani)); 01523 S_REPLACE(tc->cid.cid_rdnis, ast_strdup(chan->cid.cid_rdnis)); 01524 01525 /* Copy language from incoming to outgoing */ 01526 ast_string_field_set(tc, language, chan->language); 01527 ast_string_field_set(tc, accountcode, chan->accountcode); 01528 tc->cdrflags = chan->cdrflags; 01529 if (ast_strlen_zero(tc->musicclass)) 01530 ast_string_field_set(tc, musicclass, chan->musicclass); 01531 /* Pass callingpres, type of number, tns, ADSI CPE, transfer capability */ 01532 tc->cid.cid_pres = chan->cid.cid_pres; 01533 tc->cid.cid_ton = chan->cid.cid_ton; 01534 tc->cid.cid_tns = chan->cid.cid_tns; 01535 tc->cid.cid_ani2 = chan->cid.cid_ani2; 01536 tc->adsicpe = chan->adsicpe; 01537 tc->transfercapability = chan->transfercapability; 01538 01539 /* If we have an outbound group, set this peer channel to it */ 01540 if (outbound_group) 01541 ast_app_group_set_channel(tc, outbound_group); 01542 01543 /* Inherit context and extension */ 01544 if (!ast_strlen_zero(chan->macrocontext)) 01545 ast_copy_string(tc->dialcontext, chan->macrocontext, sizeof(tc->dialcontext)); 01546 else 01547 ast_copy_string(tc->dialcontext, chan->context, sizeof(tc->dialcontext)); 01548 if (!ast_strlen_zero(chan->macroexten)) 01549 ast_copy_string(tc->exten, chan->macroexten, sizeof(tc->exten)); 01550 else 01551 ast_copy_string(tc->exten, chan->exten, sizeof(tc->exten)); 01552 01553 res = ast_call(tc, numsubst, 0); /* Place the call, but don't wait on the answer */ 01554 01555 /* Save the info in cdr's that we called them */ 01556 if (chan->cdr) 01557 ast_cdr_setdestchan(chan->cdr, tc->name); 01558 01559 /* check the results of ast_call */ 01560 if (res) { 01561 /* Again, keep going even if there's an error */ 01562 ast_debug(1, "ast call on peer returned %d\n", res); 01563 ast_verb(3, "Couldn't call %s\n", numsubst); 01564 if (tc->hangupcause) { 01565 chan->hangupcause = tc->hangupcause; 01566 } 01567 ast_hangup(tc); 01568 tc = NULL; 01569 ast_free(tmp); 01570 continue; 01571 } else { 01572 senddialevent(chan, tc, numsubst); 01573 ast_verb(3, "Called %s\n", numsubst); 01574 if (!ast_test_flag64(peerflags, OPT_ORIGINAL_CLID)) 01575 ast_set_callerid(tc, S_OR(chan->macroexten, chan->exten), get_cid_name(cidname, sizeof(cidname), chan), NULL); 01576 } 01577 /* Put them in the list of outgoing thingies... We're ready now. 01578 XXX If we're forcibly removed, these outgoing calls won't get 01579 hung up XXX */ 01580 ast_set_flag64(tmp, DIAL_STILLGOING); 01581 tmp->chan = tc; 01582 tmp->next = outgoing; 01583 outgoing = tmp; 01584 /* If this line is up, don't try anybody else */ 01585 if (outgoing->chan->_state == AST_STATE_UP) 01586 break; 01587 } 01588 01589 if (ast_strlen_zero(args.timeout)) { 01590 to = -1; 01591 } else { 01592 to = atoi(args.timeout); 01593 if (to > 0) 01594 to *= 1000; 01595 else 01596 ast_log(LOG_WARNING, "Invalid timeout specified: '%s'\n", args.timeout); 01597 } 01598 01599 if (!outgoing) { 01600 strcpy(pa.status, "CHANUNAVAIL"); 01601 if (fulldial == num_dialed) { 01602 res = -1; 01603 goto out; 01604 } 01605 } else { 01606 /* Our status will at least be NOANSWER */ 01607 strcpy(pa.status, "NOANSWER"); 01608 if (ast_test_flag64(outgoing, OPT_MUSICBACK)) { 01609 moh = 1; 01610 if (!ast_strlen_zero(opt_args[OPT_ARG_MUSICBACK])) { 01611 char *original_moh = ast_strdupa(chan->musicclass); 01612 ast_string_field_set(chan, musicclass, opt_args[OPT_ARG_MUSICBACK]); 01613 ast_moh_start(chan, opt_args[OPT_ARG_MUSICBACK], NULL); 01614 ast_string_field_set(chan, musicclass, original_moh); 01615 } else { 01616 ast_moh_start(chan, NULL, NULL); 01617 } 01618 ast_indicate(chan, AST_CONTROL_PROGRESS); 01619 } else if (ast_test_flag64(outgoing, OPT_RINGBACK)) { 01620 ast_indicate(chan, AST_CONTROL_RINGING); 01621 sentringing++; 01622 } 01623 } 01624 01625 peer = wait_for_answer(chan, outgoing, &to, peerflags, &pa, &num, &result); 01626 01627 /* The ast_channel_datastore_remove() function could fail here if the 01628 * datastore was moved to another channel during a masquerade. If this is 01629 * the case, don't free the datastore here because later, when the channel 01630 * to which the datastore was moved hangs up, it will attempt to free this 01631 * datastore again, causing a crash 01632 */ 01633 if (!ast_channel_datastore_remove(chan, datastore)) 01634 ast_channel_datastore_free(datastore); 01635 if (!peer) { 01636 if (result) { 01637 res = result; 01638 } else if (to) { /* Musta gotten hung up */ 01639 res = -1; 01640 } else { /* Nobody answered, next please? */ 01641 res = 0; 01642 } 01643 /* almost done, although the 'else' block is 400 lines */ 01644 } else { 01645 const char *number; 01646 01647 strcpy(pa.status, "ANSWER"); 01648 pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status); 01649 /* Ah ha! Someone answered within the desired timeframe. Of course after this 01650 we will always return with -1 so that it is hung up properly after the 01651 conversation. */ 01652 hanguptree(outgoing, peer, 1); 01653 outgoing = NULL; 01654 /* If appropriate, log that we have a destination channel */ 01655 if (chan->cdr) 01656 ast_cdr_setdestchan(chan->cdr, peer->name); 01657 if (peer->name) 01658 pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", peer->name); 01659 01660 number = pbx_builtin_getvar_helper(peer, "DIALEDPEERNUMBER"); 01661 if (!number) 01662 number = numsubst; 01663 pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", number); 01664 if (!ast_strlen_zero(args.url) && ast_channel_supports_html(peer) ) { 01665 ast_debug(1, "app_dial: sendurl=%s.\n", args.url); 01666 ast_channel_sendurl( peer, args.url ); 01667 } 01668 if ( (ast_test_flag64(&opts, OPT_PRIVACY) || ast_test_flag64(&opts, OPT_SCREENING)) && pa.privdb_val == AST_PRIVACY_UNKNOWN) { 01669 if (do_privacy(chan, peer, &opts, opt_args, &pa)) { 01670 res = 0; 01671 goto out; 01672 } 01673 } 01674 if (!ast_test_flag64(&opts, OPT_ANNOUNCE) || ast_strlen_zero(opt_args[OPT_ARG_ANNOUNCE])) { 01675 res = 0; 01676 } else { 01677 int digit = 0; 01678 /* Start autoservice on the other chan */ 01679 res = ast_autoservice_start(chan); 01680 /* Now Stream the File */ 01681 if (!res) 01682 res = ast_streamfile(peer, opt_args[OPT_ARG_ANNOUNCE], peer->language); 01683 if (!res) { 01684 digit = ast_waitstream(peer, AST_DIGIT_ANY); 01685 } 01686 /* Ok, done. stop autoservice */ 01687 res = ast_autoservice_stop(chan); 01688 if (digit > 0 && !res) 01689 res = ast_senddigit(chan, digit, 0); 01690 else 01691 res = digit; 01692 01693 } 01694 01695 if (chan && peer && ast_test_flag64(&opts, OPT_GOTO) && !ast_strlen_zero(opt_args[OPT_ARG_GOTO])) { 01696 replace_macro_delimiter(opt_args[OPT_ARG_GOTO]); 01697 ast_parseable_goto(chan, opt_args[OPT_ARG_GOTO]); 01698 /* peer goes to the same context and extension as chan, so just copy info from chan*/ 01699 ast_copy_string(peer->context, chan->context, sizeof(peer->context)); 01700 ast_copy_string(peer->exten, chan->exten, sizeof(peer->exten)); 01701 peer->priority = chan->priority + 2; 01702 ast_pbx_start(peer); 01703 hanguptree(outgoing, NULL, ast_test_flag64(&opts, OPT_CANCEL_ELSEWHERE) ? 1 : 0); 01704 if (continue_exec) 01705 *continue_exec = 1; 01706 res = 0; 01707 goto done; 01708 } 01709 01710 if (ast_test_flag64(&opts, OPT_CALLEE_MACRO) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_MACRO])) { 01711 struct ast_app *theapp; 01712 const char *macro_result; 01713 01714 res = ast_autoservice_start(chan); 01715 if (res) { 01716 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n"); 01717 res = -1; 01718 } 01719 01720 theapp = pbx_findapp("Macro"); 01721 01722 if (theapp && !res) { /* XXX why check res here ? */ 01723 /* Set peer->exten and peer->context so that MACRO_EXTEN and MACRO_CONTEXT get set */ 01724 ast_copy_string(peer->context, chan->context, sizeof(peer->context)); 01725 ast_copy_string(peer->exten, chan->exten, sizeof(peer->exten)); 01726 01727 replace_macro_delimiter(opt_args[OPT_ARG_CALLEE_MACRO]); 01728 res = pbx_exec(peer, theapp, opt_args[OPT_ARG_CALLEE_MACRO]); 01729 ast_debug(1, "Macro exited with status %d\n", res); 01730 res = 0; 01731 } else { 01732 ast_log(LOG_ERROR, "Could not find application Macro\n"); 01733 res = -1; 01734 } 01735 01736 if (ast_autoservice_stop(chan) < 0) { 01737 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n"); 01738 res = -1; 01739 } 01740 01741 if (!res && (macro_result = pbx_builtin_getvar_helper(peer, "MACRO_RESULT"))) { 01742 char *macro_transfer_dest; 01743 01744 if (!strcasecmp(macro_result, "BUSY")) { 01745 ast_copy_string(pa.status, macro_result, sizeof(pa.status)); 01746 ast_set_flag64(peerflags, OPT_GO_ON); 01747 res = -1; 01748 } else if (!strcasecmp(macro_result, "CONGESTION") || !strcasecmp(macro_result, "CHANUNAVAIL")) { 01749 ast_copy_string(pa.status, macro_result, sizeof(pa.status)); 01750 ast_set_flag64(peerflags, OPT_GO_ON); 01751 res = -1; 01752 } else if (!strcasecmp(macro_result, "CONTINUE")) { 01753 /* hangup peer and keep chan alive assuming the macro has changed 01754 the context / exten / priority or perhaps 01755 the next priority in the current exten is desired. 01756 */ 01757 ast_set_flag64(peerflags, OPT_GO_ON); 01758 res = -1; 01759 } else if (!strcasecmp(macro_result, "ABORT")) { 01760 /* Hangup both ends unless the caller has the g flag */ 01761 res = -1; 01762 } else if (!strncasecmp(macro_result, "GOTO:", 5) && (macro_transfer_dest = ast_strdupa(macro_result + 5))) { 01763 res = -1; 01764 /* perform a transfer to a new extension */ 01765 if (strchr(macro_transfer_dest, '^')) { /* context^exten^priority*/ 01766 replace_macro_delimiter(macro_transfer_dest); 01767 if (!ast_parseable_goto(chan, macro_transfer_dest)) 01768 ast_set_flag64(peerflags, OPT_GO_ON); 01769 } 01770 } 01771 } 01772 } 01773 01774 if (ast_test_flag64(&opts, OPT_CALLEE_GOSUB) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GOSUB])) { 01775 struct ast_app *theapp; 01776 const char *gosub_result; 01777 char *gosub_args, *gosub_argstart; 01778 01779 res = ast_autoservice_start(chan); 01780 if (res) { 01781 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n"); 01782 res = -1; 01783 } 01784 01785 theapp = pbx_findapp("Gosub"); 01786 01787 if (theapp && !res) { /* XXX why check res here ? */ 01788 replace_macro_delimiter(opt_args[OPT_ARG_CALLEE_GOSUB]); 01789 01790 /* Set where we came from */ 01791 ast_copy_string(peer->context, "app_dial_gosub_virtual_context", sizeof(peer->context)); 01792 ast_copy_string(peer->exten, "s", sizeof(peer->exten)); 01793 peer->priority = 0; 01794 01795 gosub_argstart = strchr(opt_args[OPT_ARG_CALLEE_GOSUB], ','); 01796 if (gosub_argstart) { 01797 *gosub_argstart = 0; 01798 if (asprintf(&gosub_args, "%s,s,1(%s)", opt_args[OPT_ARG_CALLEE_GOSUB], gosub_argstart + 1) < 0) { 01799 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 01800 gosub_args = NULL; 01801 } 01802 *gosub_argstart = ','; 01803 } else { 01804 if (asprintf(&gosub_args, "%s,s,1", opt_args[OPT_ARG_CALLEE_GOSUB]) < 0) { 01805 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 01806 gosub_args = NULL; 01807 } 01808 } 01809 01810 if (gosub_args) { 01811 res = pbx_exec(peer, theapp, gosub_args); 01812 if (!res) { 01813 struct ast_pbx_args args; 01814 /* A struct initializer fails to compile for this case ... */ 01815 memset(&args, 0, sizeof(args)); 01816 args.no_hangup_chan = 1; 01817 ast_pbx_run_args(peer, &args); 01818 } 01819 ast_free(gosub_args); 01820 ast_debug(1, "Gosub exited with status %d\n", res); 01821 } else { 01822 ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n"); 01823 } 01824 01825 res = 0; 01826 } else { 01827 ast_log(LOG_ERROR, "Could not find application Gosub\n"); 01828 res = -1; 01829 } 01830 01831 if (ast_autoservice_stop(chan) < 0) { 01832 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n"); 01833 res = -1; 01834 } 01835 01836 if (!res && (gosub_result = pbx_builtin_getvar_helper(peer, "GOSUB_RESULT"))) { 01837 char *gosub_transfer_dest; 01838 01839 if (!strcasecmp(gosub_result, "BUSY")) { 01840 ast_copy_string(pa.status, gosub_result, sizeof(pa.status)); 01841 ast_set_flag64(peerflags, OPT_GO_ON); 01842 res = -1; 01843 } else if (!strcasecmp(gosub_result, "CONGESTION") || !strcasecmp(gosub_result, "CHANUNAVAIL")) { 01844 ast_copy_string(pa.status, gosub_result, sizeof(pa.status)); 01845 ast_set_flag64(peerflags, OPT_GO_ON); 01846 res = -1; 01847 } else if (!strcasecmp(gosub_result, "CONTINUE")) { 01848 /* hangup peer and keep chan alive assuming the macro has changed 01849 the context / exten / priority or perhaps 01850 the next priority in the current exten is desired. 01851 */ 01852 ast_set_flag64(peerflags, OPT_GO_ON); 01853 res = -1; 01854 } else if (!strcasecmp(gosub_result, "ABORT")) { 01855 /* Hangup both ends unless the caller has the g flag */ 01856 res = -1; 01857 } else if (!strncasecmp(gosub_result, "GOTO:", 5) && (gosub_transfer_dest = ast_strdupa(gosub_result + 5))) { 01858 res = -1; 01859 /* perform a transfer to a new extension */ 01860 if (strchr(gosub_transfer_dest, '^')) { /* context^exten^priority*/ 01861 replace_macro_delimiter(gosub_transfer_dest); 01862 if (!ast_parseable_goto(chan, gosub_transfer_dest)) 01863 ast_set_flag64(peerflags, OPT_GO_ON); 01864 } 01865 } 01866 } 01867 } 01868 01869 if (!res) { 01870 if (calldurationlimit > 0) { 01871 peer->whentohangup = time(NULL) + calldurationlimit; 01872 } 01873 if (!ast_strlen_zero(dtmfcalled)) { 01874 ast_verb(3, "Sending DTMF '%s' to the called party.\n", dtmfcalled); 01875 res = ast_dtmf_stream(peer, chan, dtmfcalled, 250, 0); 01876 } 01877 if (!ast_strlen_zero(dtmfcalling)) { 01878 ast_verb(3, "Sending DTMF '%s' to the calling party.\n", dtmfcalling); 01879 res = ast_dtmf_stream(chan, peer, dtmfcalling, 250, 0); 01880 } 01881 } 01882 01883 if (res) { /* some error */ 01884 res = -1; 01885 } else { 01886 if (ast_test_flag64(peerflags, OPT_CALLEE_TRANSFER)) 01887 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 01888 if (ast_test_flag64(peerflags, OPT_CALLER_TRANSFER)) 01889 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 01890 if (ast_test_flag64(peerflags, OPT_CALLEE_HANGUP)) 01891 ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT); 01892 if (ast_test_flag64(peerflags, OPT_CALLER_HANGUP)) 01893 ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT); 01894 if (ast_test_flag64(peerflags, OPT_CALLEE_MONITOR)) 01895 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON); 01896 if (ast_test_flag64(peerflags, OPT_CALLER_MONITOR)) 01897 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON); 01898 if (ast_test_flag64(peerflags, OPT_CALLEE_PARK)) 01899 ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL); 01900 if (ast_test_flag64(peerflags, OPT_CALLER_PARK)) 01901 ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL); 01902 if (ast_test_flag64(peerflags, OPT_CALLEE_MIXMONITOR)) 01903 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMIXMON); 01904 if (ast_test_flag64(peerflags, OPT_CALLER_MIXMONITOR)) 01905 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMIXMON); 01906 if (ast_test_flag64(peerflags, OPT_GO_ON)) 01907 ast_set_flag(&(config.features_caller), AST_FEATURE_NO_H_EXTEN); 01908 01909 config.end_bridge_callback = end_bridge_callback; 01910 config.end_bridge_callback_data = chan; 01911 config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup; 01912 01913 if (moh) { 01914 moh = 0; 01915 ast_moh_stop(chan); 01916 } else if (sentringing) { 01917 sentringing = 0; 01918 ast_indicate(chan, -1); 01919 } 01920 /* Be sure no generators are left on it */ 01921 ast_deactivate_generator(chan); 01922 /* Make sure channels are compatible */ 01923 res = ast_channel_make_compatible(chan, peer); 01924 if (res < 0) { 01925 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", chan->name, peer->name); 01926 ast_hangup(peer); 01927 res = -1; 01928 goto done; 01929 } 01930 if (opermode && !strncmp(chan->tech->type, "DAHDI", 5) && !strncmp(peer->name, "DAHDI", 5)) { 01931 /* what's this special handling for dahdi <-> dahdi ? 01932 * A: dahdi to dahdi calls are natively bridged at the kernel driver 01933 * level, so we need to ensure that this mode gets propagated 01934 * all the way down. */ 01935 struct oprmode oprmode; 01936 01937 oprmode.peer = peer; 01938 oprmode.mode = opermode; 01939 01940 ast_channel_setoption(chan, AST_OPTION_OPRMODE, &oprmode, sizeof(oprmode), 0); 01941 } 01942 res = ast_bridge_call(chan, peer, &config); 01943 } 01944 01945 strcpy(peer->context, chan->context); 01946 01947 if (ast_test_flag64(&opts, OPT_PEER_H) && ast_exists_extension(peer, peer->context, "h", 1, peer->cid.cid_num)) { 01948 int autoloopflag; 01949 int found; 01950 strcpy(peer->exten, "h"); 01951 peer->priority = 1; 01952 autoloopflag = ast_test_flag(peer, AST_FLAG_IN_AUTOLOOP); /* save value to restore at the end */ 01953 ast_set_flag(peer, AST_FLAG_IN_AUTOLOOP); 01954 01955 while ((res = ast_spawn_extension(peer, peer->context, peer->exten, peer->priority, peer->cid.cid_num, &found, 1)) == 0) 01956 peer->priority++; 01957 01958 if (found && res) { 01959 /* Something bad happened, or a hangup has been requested. */ 01960 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", peer->context, peer->exten, peer->priority, peer->name); 01961 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", peer->context, peer->exten, peer->priority, peer->name); 01962 } 01963 ast_set2_flag(peer, autoloopflag, AST_FLAG_IN_AUTOLOOP); /* set it back the way it was */ 01964 } 01965 if (!ast_check_hangup(chan)) 01966 chan->hangupcause = peer->hangupcause; 01967 ast_hangup(peer); 01968 } 01969 out: 01970 if (moh) { 01971 moh = 0; 01972 ast_moh_stop(chan); 01973 } else if (sentringing) { 01974 sentringing = 0; 01975 ast_indicate(chan, -1); 01976 } 01977 ast_channel_early_bridge(chan, NULL); 01978 hanguptree(outgoing, NULL, 0); /* In this case, there's no answer anywhere */ 01979 pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status); 01980 senddialendevent(chan, pa.status); 01981 ast_debug(1, "Exiting with DIALSTATUS=%s.\n", pa.status); 01982 01983 if (ast_test_flag64(peerflags, OPT_GO_ON) && !ast_check_hangup(chan)) { 01984 if (calldurationlimit) 01985 chan->whentohangup = 0; 01986 res = 0; 01987 } 01988 done: 01989 return res; 01990 }
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_make_compatible(), 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, 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 = pbx_builtin_getvar_helper(c, "FORWARD_CONTEXT"); 00501 if (ast_strlen_zero(forward_context)) { 00502 forward_context = NULL; 00503 } 00504 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", c->call_forward, forward_context ? forward_context : c->context); 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, | |||
unsigned int * | calldurationlimit | |||
) | [static] |
Definition at line 918 of file app_dial.c.
References AST_FEATURE_PLAY_WARNING, ast_log(), ast_set_flag, ast_strdupa, ast_true(), ast_verb, chan, config, LOG_WARNING, pbx_builtin_getvar_helper(), S_OR, strsep(), and var.
Referenced by dial_exec_full().
00920 { 00921 char *stringp = ast_strdupa(parse); 00922 char *limit_str, *warning_str, *warnfreq_str; 00923 const char *var; 00924 int play_to_caller = 0, play_to_callee = 0; 00925 int delta; 00926 00927 limit_str = strsep(&stringp, ":"); 00928 warning_str = strsep(&stringp, ":"); 00929 warnfreq_str = strsep(&stringp, ":"); 00930 00931 config->timelimit = atol(limit_str); 00932 if (warning_str) 00933 config->play_warning = atol(warning_str); 00934 if (warnfreq_str) 00935 config->warning_freq = atol(warnfreq_str); 00936 00937 if (!config->timelimit) { 00938 ast_log(LOG_WARNING, "Dial does not accept L(%s), hanging up.\n", limit_str); 00939 config->timelimit = config->play_warning = config->warning_freq = 0; 00940 config->warning_sound = NULL; 00941 return -1; /* error */ 00942 } else if ( (delta = config->play_warning - config->timelimit) > 0) { 00943 int w = config->warning_freq; 00944 00945 /* If the first warning is requested _after_ the entire call would end, 00946 and no warning frequency is requested, then turn off the warning. If 00947 a warning frequency is requested, reduce the 'first warning' time by 00948 that frequency until it falls within the call's total time limit. 00949 Graphically: 00950 timelim->| delta |<-playwarning 00951 0__________________|_________________| 00952 | w | | | | 00953 00954 so the number of intervals to cut is 1+(delta-1)/w 00955 */ 00956 00957 if (w == 0) { 00958 config->play_warning = 0; 00959 } else { 00960 config->play_warning -= w * ( 1 + (delta-1)/w ); 00961 if (config->play_warning < 1) 00962 config->play_warning = config->warning_freq = 0; 00963 } 00964 } 00965 00966 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER"); 00967 play_to_caller = var ? ast_true(var) : 1; 00968 00969 var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE"); 00970 play_to_callee = var ? ast_true(var) : 0; 00971 00972 if (!play_to_caller && !play_to_callee) 00973 play_to_caller = 1; 00974 00975 var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE"); 00976 config->warning_sound = S_OR(var, "timeleft"); 00977 00978 /* The code looking at config wants a NULL, not just "", to decide 00979 * that the message should not be played, so we replace "" with NULL. 00980 * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is 00981 * not found. 00982 */ 00983 var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE"); 00984 config->end_sound = S_OR(var, NULL); 00985 var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE"); 00986 config->start_sound = S_OR(var, NULL); 00987 00988 /* undo effect of S(x) in case they are both used */ 00989 *calldurationlimit = 0; 00990 /* more efficient to do it like S(x) does since no advanced opts */ 00991 if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) { 00992 if (config->timelimit > 1000) { 00993 *calldurationlimit = config->timelimit / 1000; 00994 } else if (config->timelimit > 0) { 00995 /* Not enough granularity to make it less, but we can't use the special value 0 */ 00996 *calldurationlimit = 1; 00997 } 00998 ast_verb(3, "Setting call duration limit to %d seconds.\n", 00999 *calldurationlimit); 01000 config->timelimit = play_to_caller = play_to_callee = 01001 config->play_warning = config->warning_freq = 0; 01002 } else { 01003 ast_verb(3, "Limit Data for this call:\n"); 01004 ast_verb(4, "timelimit = %ld\n", config->timelimit); 01005 ast_verb(4, "play_warning = %ld\n", config->play_warning); 01006 ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no"); 01007 ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no"); 01008 ast_verb(4, "warning_freq = %ld\n", config->warning_freq); 01009 ast_verb(4, "start_sound = %s\n", S_OR(config->start_sound, "")); 01010 ast_verb(4, "warning_sound = %s\n", config->warning_sound); 01011 ast_verb(4, "end_sound = %s\n", S_OR(config->end_sound, "")); 01012 } 01013 if (play_to_caller) 01014 ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); 01015 if (play_to_callee) 01016 ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); 01017 return 0; 01018 }
static void end_bridge_callback | ( | void * | data | ) | [static] |
Definition at line 1254 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().
01255 { 01256 char buf[80]; 01257 time_t end; 01258 struct ast_channel *chan = data; 01259 01260 if (!chan->cdr) { 01261 return; 01262 } 01263 01264 time(&end); 01265 01266 ast_channel_lock(chan); 01267 if (chan->cdr->answer.tv_sec) { 01268 snprintf(buf, sizeof(buf), "%ld", end - chan->cdr->answer.tv_sec); 01269 pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf); 01270 } 01271 01272 if (chan->cdr->start.tv_sec) { 01273 snprintf(buf, sizeof(buf), "%ld", end - chan->cdr->start.tv_sec); 01274 pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf); 01275 } 01276 ast_channel_unlock(chan); 01277 }
static void end_bridge_callback_data_fixup | ( | struct ast_bridge_config * | bconfig, | |
struct ast_channel * | originator, | |||
struct ast_channel * | terminator | |||
) | [static] |
Definition at line 1279 of file app_dial.c.
References ast_bridge_config::end_bridge_callback_data.
Referenced by app_exec(), and dial_exec_full().
01279 { 01280 bconfig->end_bridge_callback_data = originator; 01281 }
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 379 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.
00380 { 00381 struct ast_cdr *cdr = num->chan->cdr; 00382 00383 switch(cause) { 00384 case AST_CAUSE_BUSY: 00385 if (cdr) 00386 ast_cdr_busy(cdr); 00387 num->busy++; 00388 break; 00389 00390 case AST_CAUSE_CONGESTION: 00391 if (cdr) 00392 ast_cdr_failed(cdr); 00393 num->congestion++; 00394 break; 00395 00396 case AST_CAUSE_NO_ROUTE_DESTINATION: 00397 case AST_CAUSE_UNREGISTERED: 00398 if (cdr) 00399 ast_cdr_failed(cdr); 00400 num->nochan++; 00401 break; 00402 00403 case AST_CAUSE_NO_ANSWER: 00404 if (cdr) { 00405 ast_cdr_noanswer(cdr); 00406 } 00407 break; 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 350 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().
00351 { 00352 /* Hang up a tree of stuff */ 00353 struct chanlist *oo; 00354 while (outgoing) { 00355 /* Hangup any existing lines we have open */ 00356 if (outgoing->chan && (outgoing->chan != exception)) { 00357 if (answered_elsewhere) 00358 ast_set_flag(outgoing->chan, AST_FLAG_ANSWERED_ELSEWHERE); 00359 ast_hangup(outgoing->chan); 00360 } 00361 oo = outgoing; 00362 outgoing = outgoing->next; 00363 ast_free(oo); 00364 } 00365 }
static int load_module | ( | void | ) | [static] |
Definition at line 2122 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().
02123 { 02124 int res; 02125 struct ast_context *con; 02126 02127 con = ast_context_find_or_create(NULL, NULL, "app_dial_gosub_virtual_context", "app_dial"); 02128 if (!con) 02129 ast_log(LOG_ERROR, "Dial virtual context 'app_dial_gosub_virtual_context' does not exist and unable to create\n"); 02130 else 02131 ast_add_extension2(con, 1, "s", 1, NULL, NULL, "NoOp", ast_strdup(""), ast_free_ptr, "app_dial"); 02132 02133 res = ast_register_application(app, dial_exec, synopsis, descrip); 02134 res |= ast_register_application(rapp, retrydial_exec, rsynopsis, rdescrip); 02135 02136 return res; 02137 }
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 2001 of file app_dial.c.
References AST_APP_ARG, AST_DECLARE_APP_ARGS, AST_DIGIT_ANY, ast_fileexists(), AST_FLAG_MOH, ast_log(), ast_moh_start(), ast_moh_stop(), 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().
02002 { 02003 char *parse; 02004 const char *context = NULL; 02005 int sleep = 0, loops = 0, res = -1; 02006 struct ast_flags64 peerflags = { 0, }; 02007 AST_DECLARE_APP_ARGS(args, 02008 AST_APP_ARG(announce); 02009 AST_APP_ARG(sleep); 02010 AST_APP_ARG(retries); 02011 AST_APP_ARG(dialdata); 02012 ); 02013 02014 if (ast_strlen_zero(data)) { 02015 ast_log(LOG_WARNING, "RetryDial requires an argument!\n"); 02016 return -1; 02017 } 02018 02019 parse = ast_strdupa(data); 02020 AST_STANDARD_APP_ARGS(args, parse); 02021 02022 if (!ast_strlen_zero(args.sleep) && (sleep = atoi(args.sleep))) 02023 sleep *= 1000; 02024 02025 if (!ast_strlen_zero(args.retries)) { 02026 loops = atoi(args.retries); 02027 } 02028 02029 if (!args.dialdata) { 02030 ast_log(LOG_ERROR, "%s requires a 4th argument (dialdata)\n", rapp); 02031 goto done; 02032 } 02033 02034 if (sleep < 1000) 02035 sleep = 10000; 02036 02037 if (!loops) 02038 loops = -1; /* run forever */ 02039 02040 context = pbx_builtin_getvar_helper(chan, "EXITCONTEXT"); 02041 02042 res = 0; 02043 while (loops) { 02044 int continue_exec; 02045 02046 chan->data = "Retrying"; 02047 if (ast_test_flag(chan, AST_FLAG_MOH)) 02048 ast_moh_stop(chan); 02049 02050 res = dial_exec_full(chan, args.dialdata, &peerflags, &continue_exec); 02051 if (continue_exec) 02052 break; 02053 02054 if (res == 0) { 02055 if (ast_test_flag64(&peerflags, OPT_DTMF_EXIT)) { 02056 if (!ast_strlen_zero(args.announce)) { 02057 if (ast_fileexists(args.announce, NULL, chan->language) > 0) { 02058 if (!(res = ast_streamfile(chan, args.announce, chan->language))) 02059 ast_waitstream(chan, AST_DIGIT_ANY); 02060 } else 02061 ast_log(LOG_WARNING, "Announce file \"%s\" specified in Retrydial does not exist\n", args.announce); 02062 } 02063 if (!res && sleep) { 02064 if (!ast_test_flag(chan, AST_FLAG_MOH)) 02065 ast_moh_start(chan, NULL, NULL); 02066 res = ast_waitfordigit(chan, sleep); 02067 } 02068 } else { 02069 if (!ast_strlen_zero(args.announce)) { 02070 if (ast_fileexists(args.announce, NULL, chan->language) > 0) { 02071 if (!(res = ast_streamfile(chan, args.announce, chan->language))) 02072 res = ast_waitstream(chan, ""); 02073 } else 02074 ast_log(LOG_WARNING, "Announce file \"%s\" specified in Retrydial does not exist\n", args.announce); 02075 } 02076 if (sleep) { 02077 if (!ast_test_flag(chan, AST_FLAG_MOH)) 02078 ast_moh_start(chan, NULL, NULL); 02079 if (!res) 02080 res = ast_waitfordigit(chan, sleep); 02081 } 02082 } 02083 } 02084 02085 if (res < 0) 02086 break; 02087 else if (res > 0) { /* Trying to send the call elsewhere (1 digit ext) */ 02088 if (onedigit_goto(chan, context, (char) res, 1)) { 02089 res = 0; 02090 break; 02091 } 02092 } 02093 loops--; 02094 } 02095 if (loops == 0) 02096 res = 0; 02097 else if (res == 1) 02098 res = 0; 02099 02100 if (ast_test_flag(chan, AST_FLAG_MOH)) 02101 ast_moh_stop(chan); 02102 done: 02103 return res; 02104 }
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 1155 of file app_dial.c.
References ast_answer(), ast_config_AST_DATA_DIR, ast_copy_string(), 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, and privacy_args::status.
Referenced by dial_exec_full().
01157 { 01158 char callerid[60]; 01159 int res; 01160 char *l; 01161 01162 if (!ast_strlen_zero(chan->cid.cid_num)) { 01163 l = ast_strdupa(chan->cid.cid_num); 01164 ast_shrink_phone_number(l); 01165 if (ast_test_flag64(opts, OPT_PRIVACY) ) { 01166 ast_verb(3, "Privacy DB is '%s', clid is '%s'\n", opt_args[OPT_ARG_PRIVACY], l); 01167 pa->privdb_val = ast_privacy_check(opt_args[OPT_ARG_PRIVACY], l); 01168 } else { 01169 ast_verb(3, "Privacy Screening, clid is '%s'\n", l); 01170 pa->privdb_val = AST_PRIVACY_UNKNOWN; 01171 } 01172 } else { 01173 char *tnam, *tn2; 01174 01175 tnam = ast_strdupa(chan->name); 01176 /* clean the channel name so slashes don't try to end up in disk file name */ 01177 for (tn2 = tnam; *tn2; tn2++) { 01178 if (*tn2 == '/') /* any other chars to be afraid of? */ 01179 *tn2 = '='; 01180 } 01181 ast_verb(3, "Privacy-- callerid is empty\n"); 01182 01183 snprintf(callerid, sizeof(callerid), "NOCALLERID_%s%s", chan->exten, tnam); 01184 l = callerid; 01185 pa->privdb_val = AST_PRIVACY_UNKNOWN; 01186 } 01187 01188 ast_copy_string(pa->privcid, l, sizeof(pa->privcid)); 01189 01190 if (strncmp(pa->privcid, "NOCALLERID", 10) != 0 && ast_test_flag64(opts, OPT_SCREEN_NOCLID)) { 01191 /* if callerid is set and OPT_SCREEN_NOCLID is set also */ 01192 ast_verb(3, "CallerID set (%s); N option set; Screening should be off\n", pa->privcid); 01193 pa->privdb_val = AST_PRIVACY_ALLOW; 01194 } else if (ast_test_flag64(opts, OPT_SCREEN_NOCLID) && strncmp(pa->privcid, "NOCALLERID", 10) == 0) { 01195 ast_verb(3, "CallerID blank; N option set; Screening should happen; dbval is %d\n", pa->privdb_val); 01196 } 01197 01198 if (pa->privdb_val == AST_PRIVACY_DENY) { 01199 ast_verb(3, "Privacy DB reports PRIVACY_DENY for this callerid. Dial reports unavailable\n"); 01200 ast_copy_string(pa->status, "NOANSWER", sizeof(pa->status)); 01201 return 0; 01202 } else if (pa->privdb_val == AST_PRIVACY_KILL) { 01203 ast_copy_string(pa->status, "DONTCALL", sizeof(pa->status)); 01204 return 0; /* Is this right? */ 01205 } else if (pa->privdb_val == AST_PRIVACY_TORTURE) { 01206 ast_copy_string(pa->status, "TORTURE", sizeof(pa->status)); 01207 return 0; /* is this right??? */ 01208 } else if (pa->privdb_val == AST_PRIVACY_UNKNOWN) { 01209 /* Get the user's intro, store it in priv-callerintros/$CID, 01210 unless it is already there-- this should be done before the 01211 call is actually dialed */ 01212 01213 /* make sure the priv-callerintros dir actually exists */ 01214 snprintf(pa->privintro, sizeof(pa->privintro), "%s/sounds/priv-callerintros", ast_config_AST_DATA_DIR); 01215 if ((res = ast_mkdir(pa->privintro, 0755))) { 01216 ast_log(LOG_WARNING, "privacy: can't create directory priv-callerintros: %s\n", strerror(res)); 01217 return -1; 01218 } 01219 01220 snprintf(pa->privintro, sizeof(pa->privintro), "priv-callerintros/%s", pa->privcid); 01221 if (ast_fileexists(pa->privintro, NULL, NULL ) > 0 && strncmp(pa->privcid, "NOCALLERID", 10) != 0) { 01222 /* the DELUX version of this code would allow this caller the 01223 option to hear and retape their previously recorded intro. 01224 */ 01225 } else { 01226 int duration; /* for feedback from play_and_wait */ 01227 /* the file doesn't exist yet. Let the caller submit his 01228 vocal intro for posterity */ 01229 /* priv-recordintro script: 01230 01231 "At the tone, please say your name:" 01232 01233 */ 01234 ast_answer(chan); 01235 res = ast_play_and_record(chan, "priv-recordintro", pa->privintro, 4, "gsm", &duration, 128, 2000, 0); /* NOTE: I've reduced the total time to 4 sec */ 01236 /* don't think we'll need a lock removed, we took care of 01237 conflicts by naming the pa.privintro file */ 01238 if (res == -1) { 01239 /* Delete the file regardless since they hung up during recording */ 01240 ast_filedelete(pa->privintro, NULL); 01241 if (ast_fileexists(pa->privintro, NULL, NULL) > 0) 01242 ast_log(LOG_NOTICE, "privacy: ast_filedelete didn't do its job on %s\n", pa->privintro); 01243 else 01244 ast_verb(3, "Successfully deleted %s intro file\n", pa->privintro); 01245 return -1; 01246 } 01247 if (!ast_streamfile(chan, "vm-dialout", chan->language) ) 01248 ast_waitstream(chan, ""); 01249 } 01250 } 01251 return 1; /* success */ 01252 }
static int unload_module | ( | void | ) | [static] |
Definition at line 2106 of file app_dial.c.
References ast_context_destroy(), ast_context_find(), ast_context_remove_extension2(), and ast_unregister_application().
02107 { 02108 int res; 02109 struct ast_context *con; 02110 02111 res = ast_unregister_application(app); 02112 res |= ast_unregister_application(rapp); 02113 02114 if ((con = ast_context_find("app_dial_gosub_virtual_context"))) { 02115 ast_context_remove_extension2(con, "s", 1, NULL, 0); 02116 ast_context_destroy(con, "app_dial"); /* leave nothing behind */ 02117 } 02118 02119 return res; 02120 }
static int valid_priv_reply | ( | struct ast_flags64 * | opts, | |
int | res | |||
) | [static] |
Definition at line 907 of file app_dial.c.
References ast_test_flag64, OPT_PRIVACY, and OPT_SCREENING.
00908 { 00909 if (res < '1') 00910 return 0; 00911 if (ast_test_flag64(opts, OPT_PRIVACY) && res <= '5') 00912 return 1; 00913 if (ast_test_flag64(opts, OPT_SCREENING) && res <= '4') 00914 return 1; 00915 return 0; 00916 }
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_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, ast_channel::dialcontext, ast_cdr::disposition, do_forward(), ast_channel::exten, 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_copy_string(c->dialcontext, "", sizeof(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_copy_string(c->dialcontext, "", sizeof(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 /* XXX are we sure the logic is correct ? or we should just switch on f->frametype ? */ 00784 if (f->frametype == AST_FRAME_VOICE && !ast_test_flag64(outgoing, OPT_RINGBACK|OPT_MUSICBACK)) { 00785 if (ast_write(in, f)) 00786 ast_log(LOG_WARNING, "Unable to forward voice frame\n"); 00787 } else if (f->frametype == AST_FRAME_IMAGE && !ast_test_flag64(outgoing, OPT_RINGBACK|OPT_MUSICBACK)) { 00788 if (ast_write(in, f)) 00789 ast_log(LOG_WARNING, "Unable to forward image\n"); 00790 } else if (f->frametype == AST_FRAME_TEXT && !ast_test_flag64(outgoing, OPT_RINGBACK|OPT_MUSICBACK)) { 00791 if (ast_write(in, f)) 00792 ast_log(LOG_WARNING, "Unable to send text\n"); 00793 } else if (f->frametype == AST_FRAME_HTML && !ast_test_flag64(outgoing, DIAL_NOFORWARDHTML)) { 00794 if (ast_channel_sendhtml(in, f->subclass, f->data, f->datalen) == -1) 00795 ast_log(LOG_WARNING, "Unable to send URL\n"); 00796 } 00797 } 00798 ast_frfree(f); 00799 } /* end for */ 00800 if (winner == in) { 00801 struct ast_frame *f = ast_read(in); 00802 #if 0 00803 if (f && (f->frametype != AST_FRAME_VOICE)) 00804 printf("Frame type: %d, %d\n", f->frametype, f->subclass); 00805 else if (!f || (f->frametype != AST_FRAME_VOICE)) 00806 printf("Hangup received on %s\n", in->name); 00807 #endif 00808 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) { 00809 /* Got hung up */ 00810 *to = -1; 00811 strcpy(pa->status, "CANCEL"); 00812 ast_cdr_noanswer(in->cdr); 00813 if (f) 00814 ast_frfree(f); 00815 return NULL; 00816 } 00817 00818 /* now f is guaranteed non-NULL */ 00819 if (f->frametype == AST_FRAME_DTMF) { 00820 if (ast_test_flag64(peerflags, OPT_DTMF_EXIT)) { 00821 const char *context = pbx_builtin_getvar_helper(in, "EXITCONTEXT"); 00822 if (onedigit_goto(in, context, (char) f->subclass, 1)) { 00823 ast_verb(3, "User hit %c to disconnect call.\n", f->subclass); 00824 *to = 0; 00825 ast_cdr_noanswer(in->cdr); 00826 *result = f->subclass; 00827 strcpy(pa->status, "CANCEL"); 00828 ast_frfree(f); 00829 return NULL; 00830 } 00831 } 00832 00833 if (ast_test_flag64(peerflags, OPT_CALLER_HANGUP) && 00834 detect_disconnect(in, f->subclass, featurecode)) { 00835 ast_verb(3, "User requested call disconnect.\n"); 00836 *to = 0; 00837 strcpy(pa->status, "CANCEL"); 00838 ast_cdr_noanswer(in->cdr); 00839 ast_frfree(f); 00840 return NULL; 00841 } 00842 } 00843 00844 /* Forward HTML stuff */ 00845 if (single && (f->frametype == AST_FRAME_HTML) && !ast_test_flag64(outgoing, DIAL_NOFORWARDHTML)) 00846 if (ast_channel_sendhtml(outgoing->chan, f->subclass, f->data, f->datalen) == -1) 00847 ast_log(LOG_WARNING, "Unable to send URL\n"); 00848 00849 if (single && ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_DTMF_BEGIN) || (f->frametype == AST_FRAME_DTMF_END))) { 00850 if (ast_write(outgoing->chan, f)) 00851 ast_log(LOG_WARNING, "Unable to forward voice or dtmf\n"); 00852 } 00853 if (single && (f->frametype == AST_FRAME_CONTROL) && 00854 ((f->subclass == AST_CONTROL_HOLD) || 00855 (f->subclass == AST_CONTROL_UNHOLD) || 00856 (f->subclass == AST_CONTROL_VIDUPDATE) || 00857 (f->subclass == AST_CONTROL_SRCUPDATE))) { 00858 ast_verb(3, "%s requested special control %d, passing it to %s\n", in->name, f->subclass, outgoing->chan->name); 00859 ast_indicate_data(outgoing->chan, f->subclass, f->data, f->datalen); 00860 } 00861 ast_frfree(f); 00862 } 00863 if (!*to) 00864 ast_verb(3, "Nobody picked up in %d ms\n", orig); 00865 if (!*to || ast_check_hangup(in)) 00866 ast_cdr_noanswer(in->cdr); 00867 } 00868 00869 #ifdef HAVE_EPOLL 00870 for (epollo = outgoing; epollo; epollo = epollo->next) { 00871 if (epollo->chan) 00872 ast_poll_channel_del(in, epollo->chan); 00873 } 00874 #endif 00875 00876 return peer; 00877 }
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 = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, } [static] |
Definition at line 2139 of file app_dial.c.
char* app = "Dial" [static] |
Definition at line 64 of file app_dial.c.
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 2139 of file app_dial.c.
char* descrip [static] |
Definition at line 68 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 }, [ '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 231 of file app_dial.c.
char* rdescrip [static] |
Definition at line 233 of file app_dial.c.
char* rsynopsis = "Place a call, retrying on failure allowing optional exit extension." [static] |
Definition at line 232 of file app_dial.c.
char* synopsis = "Place a call and connect to the current channel" [static] |
Definition at line 66 of file app_dial.c.