#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_engine.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"
#include "asterisk/cel.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_NOCONNECTEDLINE ((uint64_t)1 << 33) |
| #define | DIAL_NOFORWARDHTML ((uint64_t)1 << 32) |
| #define | DIAL_STILLGOING (1 << 31) |
| #define | OPT_CALLEE_GO_ON ((uint64_t)1 << 36) |
| #define | OPT_CANCEL_ELSEWHERE ((uint64_t)1 << 34) |
| #define | OPT_CANCEL_TIMEOUT ((uint64_t)1 << 37) |
| #define | OPT_PEER_H ((uint64_t)1 << 35) |
| #define | S_REPLACE(s, new_val) |
Enumerations | |
| enum | { OPT_ARG_ANNOUNCE = 0, OPT_ARG_SENDDTMF, OPT_ARG_GOTO, OPT_ARG_DURATION_LIMIT, OPT_ARG_MUSICBACK, OPT_ARG_CALLEE_MACRO, OPT_ARG_CALLEE_GOSUB, OPT_ARG_CALLEE_GO_ON, OPT_ARG_PRIVACY, OPT_ARG_DURATION_STOP, OPT_ARG_OPERMODE, OPT_ARG_ARRAY_SIZE } |
| 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_ORIGINAL_CLID = (1 << 8), OPT_DURATION_LIMIT = (1 << 9), OPT_MUSICBACK = (1 << 10), OPT_CALLEE_MACRO = (1 << 11), OPT_SCREEN_NOINTRO = (1 << 12), OPT_SCREEN_NOCALLERID = (1 << 13), OPT_IGNORE_CONNECTEDLINE = (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) } |
Functions | |
| static void | __reg_module (void) |
| static void | __unreg_module (void) |
| static void | chanlist_free (struct chanlist *outgoing) |
| static int | detect_disconnect (struct ast_channel *chan, char code, struct ast_str *featurecode) |
| static int | dial_exec (struct ast_channel *chan, const char *data) |
| static int | dial_exec_full (struct ast_channel *chan, const char *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, int *to) |
| 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, const char *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, char *dtmf_progress) |
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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, } |
| static const char | app [] = "Dial" |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| 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 << 34) }, [ 'd' ] = { .flag = OPT_DTMF_EXIT }, [ 'D' ] = { .flag = OPT_SENDDTMF , .arg_index = OPT_ARG_SENDDTMF + 1 }, [ 'e' ] = { .flag = ((uint64_t)1 << 35) }, [ 'f' ] = { .flag = OPT_FORCECLID }, [ 'F' ] = { .flag = ((uint64_t)1 << 36) , .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 }, [ 'I' ] = { .flag = OPT_IGNORE_CONNECTEDLINE }, [ '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_NOCALLERID }, [ '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 }, [ 'z' ] = { .flag = ((uint64_t)1 << 37) }, } |
| static const char | rapp [] = "RetryDial" |
Definition in file app_dial.c.
| #define AST_MAX_WATCHERS 256 |
| #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 568 of file app_dial.c.
Referenced by dial_exec_full(), do_forward(), and wait_for_answer().
| #define DIAL_NOCONNECTEDLINE ((uint64_t)1 << 33) |
| #define DIAL_NOFORWARDHTML ((uint64_t)1 << 32) |
| #define DIAL_STILLGOING (1 << 31) |
Definition at line 506 of file app_dial.c.
Referenced by dial_exec_full(), do_forward(), and wait_for_answer().
| #define OPT_CALLEE_GO_ON ((uint64_t)1 << 36) |
| #define OPT_CANCEL_ELSEWHERE ((uint64_t)1 << 34) |
| #define OPT_CANCEL_TIMEOUT ((uint64_t)1 << 37) |
| #define OPT_PEER_H ((uint64_t)1 << 35) |
| #define S_REPLACE | ( | s, | |||
| new_val | ) |
Value:
Definition at line 665 of file app_dial.c.
Referenced by begin_dial_channel(), dial_exec_full(), and do_forward().
| anonymous enum |
Definition at line 514 of file app_dial.c.
00514 { 00515 OPT_ARG_ANNOUNCE = 0, 00516 OPT_ARG_SENDDTMF, 00517 OPT_ARG_GOTO, 00518 OPT_ARG_DURATION_LIMIT, 00519 OPT_ARG_MUSICBACK, 00520 OPT_ARG_CALLEE_MACRO, 00521 OPT_ARG_CALLEE_GOSUB, 00522 OPT_ARG_CALLEE_GO_ON, 00523 OPT_ARG_PRIVACY, 00524 OPT_ARG_DURATION_STOP, 00525 OPT_ARG_OPERMODE, 00526 /* note: this entry _MUST_ be the last one in the enum */ 00527 OPT_ARG_ARRAY_SIZE, 00528 };
| anonymous enum |
Definition at line 472 of file app_dial.c.
00472 { 00473 OPT_ANNOUNCE = (1 << 0), 00474 OPT_RESETCDR = (1 << 1), 00475 OPT_DTMF_EXIT = (1 << 2), 00476 OPT_SENDDTMF = (1 << 3), 00477 OPT_FORCECLID = (1 << 4), 00478 OPT_GO_ON = (1 << 5), 00479 OPT_CALLEE_HANGUP = (1 << 6), 00480 OPT_CALLER_HANGUP = (1 << 7), 00481 OPT_ORIGINAL_CLID = (1 << 8), 00482 OPT_DURATION_LIMIT = (1 << 9), 00483 OPT_MUSICBACK = (1 << 10), 00484 OPT_CALLEE_MACRO = (1 << 11), 00485 OPT_SCREEN_NOINTRO = (1 << 12), 00486 OPT_SCREEN_NOCALLERID = (1 << 13), 00487 OPT_IGNORE_CONNECTEDLINE = (1 << 14), 00488 OPT_SCREENING = (1 << 15), 00489 OPT_PRIVACY = (1 << 16), 00490 OPT_RINGBACK = (1 << 17), 00491 OPT_DURATION_STOP = (1 << 18), 00492 OPT_CALLEE_TRANSFER = (1 << 19), 00493 OPT_CALLER_TRANSFER = (1 << 20), 00494 OPT_CALLEE_MONITOR = (1 << 21), 00495 OPT_CALLER_MONITOR = (1 << 22), 00496 OPT_GOTO = (1 << 23), 00497 OPT_OPERMODE = (1 << 24), 00498 OPT_CALLEE_PARK = (1 << 25), 00499 OPT_CALLER_PARK = (1 << 26), 00500 OPT_IGNORE_FORWARDING = (1 << 27), 00501 OPT_CALLEE_GOSUB = (1 << 28), 00502 OPT_CALLEE_MIXMONITOR = (1 << 29), 00503 OPT_CALLER_MIXMONITOR = (1 << 30), 00504 };
| static void __reg_module | ( | void | ) | [static] |
Definition at line 2501 of file app_dial.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 2501 of file app_dial.c.
| static void chanlist_free | ( | struct chanlist * | outgoing | ) | [static] |
Definition at line 586 of file app_dial.c.
References ast_free, ast_party_connected_line_free(), and chanlist::connected.
Referenced by dial_exec_full(), and hanguptree().
00587 { 00588 ast_party_connected_line_free(&outgoing->connected); 00589 ast_free(outgoing); 00590 }
| static int detect_disconnect | ( | struct ast_channel * | chan, | |
| char | code, | |||
| struct ast_str * | featurecode | |||
| ) | [static] |
Definition at line 1255 of file app_dial.c.
References ast_feature_detect(), AST_FEATURE_DISCONNECT, AST_FEATURE_RETURN_STOREDIGITS, ast_str_append(), ast_str_buffer(), ast_str_reset(), and ast_call_feature::feature_mask.
Referenced by wait_for_answer().
01256 { 01257 struct ast_flags features = { AST_FEATURE_DISCONNECT }; /* only concerned with disconnect feature */ 01258 struct ast_call_feature feature = { 0, }; 01259 int res; 01260 01261 ast_str_append(&featurecode, 1, "%c", code); 01262 01263 res = ast_feature_detect(chan, &features, ast_str_buffer(featurecode), &feature); 01264 01265 if (res != AST_FEATURE_RETURN_STOREDIGITS) { 01266 ast_str_reset(featurecode); 01267 } 01268 if (feature.feature_mask & AST_FEATURE_DISCONNECT) { 01269 return 1; 01270 } 01271 01272 return 0; 01273 }
| static int dial_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
Definition at line 2351 of file app_dial.c.
References dial_exec_full().
Referenced by load_module().
02352 { 02353 struct ast_flags64 peerflags; 02354 02355 memset(&peerflags, 0, sizeof(peerflags)); 02356 02357 return dial_exec_full(chan, data, &peerflags, NULL); 02358 }
| static int dial_exec_full | ( | struct ast_channel * | chan, | |
| const char * | data, | |||
| struct ast_flags64 * | peerflags, | |||
| int * | continue_exec | |||
| ) | [static] |
Definition at line 1559 of file app_dial.c.
References __ast_answer(), ast_channel::_state, ast_channel::accountcode, ast_channel::adsicpe, ast_party_connected_line::ani, 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_bridge_timelimit(), 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_trylock, ast_channel_unlock, ast_check_hangup(), ast_connected_line_copy_from_caller(), AST_CONTROL_PROGRESS, AST_CONTROL_RINGING, ast_copy_flags64, ast_copy_string(), ast_datastore_alloc, ast_datastore_free(), ast_deactivate_generator(), ast_debug, AST_DECLARE_APP_ARGS, AST_DIGIT_ANY, ast_dtmf_stream(), ast_exists_extension(), AST_FEATURE_AUTOMIXMON, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_NO_H_EXTEN, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, AST_FLAG_ANSWERED_ELSEWHERE, AST_FLAG_IN_AUTOLOOP, ast_free, ast_goto_if_exists(), 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_party_connected_line_copy(), ast_party_redirecting_copy(), AST_PBX_GOTO_FAILED, AST_PBX_INCOMPLETE, ast_pbx_run_args(), ast_pbx_start(), AST_PRIVACY_UNKNOWN, ast_request(), ast_rtp_instance_early_bridge_make_compatible(), ast_senddigit(), ast_set2_flag, ast_set2_flag64, ast_set_callerid(), ast_set_flag, ast_set_flag64, ast_spawn_extension(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdup, ast_strdupa, ast_streamfile(), ast_string_field_set, ast_strlen_zero(), ast_test_flag, ast_test_flag64, ast_tvadd(), ast_tvnow(), ast_tvzero(), ast_verb, ast_waitstream(), CAN_EARLY_BRIDGE, cause, ast_channel::cdr, ast_channel::cdrflags, chanlist::chan, chanlist_free(), CHANNEL_DEADLOCK_AVOIDANCE, ast_channel::cid, ast_callerid::cid_dnid, ast_callerid::cid_num, ast_callerid::cid_rdnis, ast_callerid::cid_tns, chanlist::connected, ast_channel::connected, ast_channel::context, ast_channel::data, ast_datastore::data, DATASTORE_INHERIT_FOREVER, di, dial_exec_options, DIAL_NOCONNECTEDLINE, DIAL_NOFORWARDHTML, DIAL_STILLGOING, dialcontext, dialed_interface_info, end_bridge_callback(), ast_bridge_config::end_bridge_callback, ast_bridge_config::end_bridge_callback_data, end_bridge_callback_data_fixup(), ast_bridge_config::end_bridge_callback_data_fixup, ast_bridge_config::end_sound, errno, ast_channel::exten, ast_bridge_config::features_callee, ast_bridge_config::features_caller, ast_flags64::flags, get_cid_name(), handle_cause(), ast_channel::hangupcause, hanguptree(), ast_party_connected_line::id, ast_datastore::inheritance, ast_dialed_interface::interface, ast_channel::language, ast_dialed_interface::list, LOG_ERROR, LOG_WARNING, ast_channel::macrocontext, ast_channel::macroexten, oprmode::mode, moh, musicclass, ast_channel::musicclass, ast_channel::name, ast_party_id::name, ast_channel::nativeformats, chanlist::next, ast_pbx_args::no_hangup_chan, ast_party_id::number, OPT_ANNOUNCE, OPT_ARG_ANNOUNCE, OPT_ARG_ARRAY_SIZE, OPT_ARG_CALLEE_GO_ON, OPT_ARG_CALLEE_GOSUB, OPT_ARG_CALLEE_MACRO, OPT_ARG_DURATION_LIMIT, OPT_ARG_DURATION_STOP, OPT_ARG_GOTO, OPT_ARG_OPERMODE, OPT_ARG_PRIVACY, OPT_ARG_SENDDTMF, OPT_CALLEE_GO_ON, OPT_CALLEE_GOSUB, OPT_CALLEE_HANGUP, OPT_CALLEE_MACRO, OPT_CALLEE_MIXMONITOR, OPT_CALLEE_MONITOR, OPT_CALLEE_PARK, OPT_CALLEE_TRANSFER, OPT_CALLER_HANGUP, OPT_CALLER_MIXMONITOR, OPT_CALLER_MONITOR, OPT_CALLER_PARK, OPT_CALLER_TRANSFER, OPT_CANCEL_ELSEWHERE, OPT_CANCEL_TIMEOUT, OPT_DTMF_EXIT, OPT_DURATION_LIMIT, OPT_DURATION_STOP, OPT_FORCECLID, OPT_GO_ON, OPT_GOTO, OPT_IGNORE_CONNECTEDLINE, 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, ast_channel::redirecting, replace_macro_delimiter(), S_OR, S_REPLACE, senddialendevent(), senddialevent(), privacy_args::sentringing, setup_privacy_args(), ast_bridge_config::start_sound, privacy_args::status, strsep(), ast_channel::tech, ast_channel::transfercapability, url, wait_for_answer(), ast_bridge_config::warning_sound, and ast_channel::whentohangup.
Referenced by dial_exec(), and retrydial_exec().
01560 { 01561 int res = -1; /* default: error */ 01562 char *rest, *cur; /* scan the list of destinations */ 01563 struct chanlist *outgoing = NULL; /* list of destinations */ 01564 struct ast_channel *peer; 01565 int to; /* timeout */ 01566 struct cause_args num = { chan, 0, 0, 0 }; 01567 int cause; 01568 char numsubst[256]; 01569 char cidname[AST_MAX_EXTENSION] = ""; 01570 01571 struct ast_bridge_config config = { { 0, } }; 01572 struct timeval calldurationlimit = { 0, }; 01573 char *dtmfcalled = NULL, *dtmfcalling = NULL, *dtmf_progress=NULL; 01574 struct privacy_args pa = { 01575 .sentringing = 0, 01576 .privdb_val = 0, 01577 .status = "INVALIDARGS", 01578 }; 01579 int sentringing = 0, moh = 0; 01580 const char *outbound_group = NULL; 01581 int result = 0; 01582 char *parse; 01583 int opermode = 0; 01584 AST_DECLARE_APP_ARGS(args, 01585 AST_APP_ARG(peers); 01586 AST_APP_ARG(timeout); 01587 AST_APP_ARG(options); 01588 AST_APP_ARG(url); 01589 ); 01590 struct ast_flags64 opts = { 0, }; 01591 char *opt_args[OPT_ARG_ARRAY_SIZE]; 01592 struct ast_datastore *datastore = NULL; 01593 int fulldial = 0, num_dialed = 0; 01594 01595 /* Reset all DIAL variables back to blank, to prevent confusion (in case we don't reset all of them). */ 01596 pbx_builtin_setvar_helper(chan, "DIALSTATUS", ""); 01597 pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", ""); 01598 pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", ""); 01599 pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", ""); 01600 pbx_builtin_setvar_helper(chan, "DIALEDTIME", ""); 01601 01602 if (ast_strlen_zero(data)) { 01603 ast_log(LOG_WARNING, "Dial requires an argument (technology/number)\n"); 01604 pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status); 01605 return -1; 01606 } 01607 01608 parse = ast_strdupa(data); 01609 01610 AST_STANDARD_APP_ARGS(args, parse); 01611 01612 if (!ast_strlen_zero(args.options) && 01613 ast_app_parse_options64(dial_exec_options, &opts, opt_args, args.options)) { 01614 pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status); 01615 goto done; 01616 } 01617 01618 if (ast_strlen_zero(args.peers)) { 01619 ast_log(LOG_WARNING, "Dial requires an argument (technology/number)\n"); 01620 pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status); 01621 goto done; 01622 } 01623 01624 if (ast_test_flag64(&opts, OPT_OPERMODE)) { 01625 opermode = ast_strlen_zero(opt_args[OPT_ARG_OPERMODE]) ? 1 : atoi(opt_args[OPT_ARG_OPERMODE]); 01626 ast_verb(3, "Setting operator services mode to %d.\n", opermode); 01627 } 01628 01629 if (ast_test_flag64(&opts, OPT_DURATION_STOP) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_STOP])) { 01630 calldurationlimit.tv_sec = atoi(opt_args[OPT_ARG_DURATION_STOP]); 01631 if (!calldurationlimit.tv_sec) { 01632 ast_log(LOG_WARNING, "Dial does not accept S(%s), hanging up.\n", opt_args[OPT_ARG_DURATION_STOP]); 01633 pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status); 01634 goto done; 01635 } 01636 ast_verb(3, "Setting call duration limit to %.3lf seconds.\n", calldurationlimit.tv_sec + calldurationlimit.tv_usec / 1000000.0); 01637 } 01638 01639 if (ast_test_flag64(&opts, OPT_SENDDTMF) && !ast_strlen_zero(opt_args[OPT_ARG_SENDDTMF])) { 01640 dtmf_progress = opt_args[OPT_ARG_SENDDTMF]; 01641 dtmfcalled = strsep(&dtmf_progress, ":"); 01642 dtmfcalling = strsep(&dtmf_progress, ":"); 01643 } 01644 01645 if (ast_test_flag64(&opts, OPT_DURATION_LIMIT) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])) { 01646 if (ast_bridge_timelimit(chan, &config, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit)) 01647 goto done; 01648 } 01649 01650 if (ast_test_flag64(&opts, OPT_RESETCDR) && chan->cdr) 01651 ast_cdr_reset(chan->cdr, NULL); 01652 if (ast_test_flag64(&opts, OPT_PRIVACY) && ast_strlen_zero(opt_args[OPT_ARG_PRIVACY])) 01653 opt_args[OPT_ARG_PRIVACY] = ast_strdupa(chan->exten); 01654 01655 if (ast_test_flag64(&opts, OPT_PRIVACY) || ast_test_flag64(&opts, OPT_SCREENING)) { 01656 res = setup_privacy_args(&pa, &opts, opt_args, chan); 01657 if (res <= 0) 01658 goto out; 01659 res = -1; /* reset default */ 01660 } 01661 01662 if (ast_test_flag64(&opts, OPT_DTMF_EXIT) || ast_test_flag64(&opts, OPT_CALLER_HANGUP)) { 01663 __ast_answer(chan, 0, 0); 01664 } 01665 01666 if (continue_exec) 01667 *continue_exec = 0; 01668 01669 /* If a channel group has been specified, get it for use when we create peer channels */ 01670 01671 ast_channel_lock(chan); 01672 if ((outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP_ONCE"))) { 01673 outbound_group = ast_strdupa(outbound_group); 01674 pbx_builtin_setvar_helper(chan, "OUTBOUND_GROUP_ONCE", NULL); 01675 } else if ((outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP"))) { 01676 outbound_group = ast_strdupa(outbound_group); 01677 } 01678 ast_channel_unlock(chan); 01679 ast_copy_flags64(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING | OPT_IGNORE_CONNECTEDLINE | 01680 OPT_CANCEL_TIMEOUT | OPT_ANNOUNCE | OPT_CALLEE_MACRO | OPT_CALLEE_GOSUB); 01681 01682 /* loop through the list of dial destinations */ 01683 rest = args.peers; 01684 while ((cur = strsep(&rest, "&")) ) { 01685 struct chanlist *tmp; 01686 struct ast_channel *tc; /* channel for this destination */ 01687 /* Get a technology/[device:]number pair */ 01688 char *number = cur; 01689 char *interface = ast_strdupa(number); 01690 char *tech = strsep(&number, "/"); 01691 /* find if we already dialed this interface */ 01692 struct ast_dialed_interface *di; 01693 AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces; 01694 num_dialed++; 01695 if (!number) { 01696 ast_log(LOG_WARNING, "Dial argument takes format (technology/[device:]number1)\n"); 01697 goto out; 01698 } 01699 if (!(tmp = ast_calloc(1, sizeof(*tmp)))) 01700 goto out; 01701 if (opts.flags) { 01702 ast_copy_flags64(tmp, &opts, 01703 OPT_CANCEL_ELSEWHERE | 01704 OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER | 01705 OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP | 01706 OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR | 01707 OPT_CALLEE_PARK | OPT_CALLER_PARK | 01708 OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR | 01709 OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID); 01710 ast_set2_flag64(tmp, args.url, DIAL_NOFORWARDHTML); 01711 } 01712 ast_copy_string(numsubst, number, sizeof(numsubst)); 01713 /* Request the peer */ 01714 01715 ast_channel_lock(chan); 01716 datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL); 01717 /* If the incoming channel has previously had connected line information 01718 * set on it (perhaps through the CONNECTED_LINE dialplan function) then 01719 * seed the calllist's connected line information with this previously 01720 * acquired info 01721 */ 01722 if (chan->connected.id.number) { 01723 ast_party_connected_line_copy(&tmp->connected, &chan->connected); 01724 } 01725 ast_channel_unlock(chan); 01726 01727 if (datastore) 01728 dialed_interfaces = datastore->data; 01729 else { 01730 if (!(datastore = ast_datastore_alloc(&dialed_interface_info, NULL))) { 01731 ast_log(LOG_WARNING, "Unable to create channel datastore for dialed interfaces. Aborting!\n"); 01732 chanlist_free(tmp); 01733 goto out; 01734 } 01735 01736 datastore->inheritance = DATASTORE_INHERIT_FOREVER; 01737 01738 if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) { 01739 ast_datastore_free(datastore); 01740 chanlist_free(tmp); 01741 goto out; 01742 } 01743 01744 datastore->data = dialed_interfaces; 01745 AST_LIST_HEAD_INIT(dialed_interfaces); 01746 01747 ast_channel_lock(chan); 01748 ast_channel_datastore_add(chan, datastore); 01749 ast_channel_unlock(chan); 01750 } 01751 01752 AST_LIST_LOCK(dialed_interfaces); 01753 AST_LIST_TRAVERSE(dialed_interfaces, di, list) { 01754 if (!strcasecmp(di->interface, interface)) { 01755 ast_log(LOG_WARNING, "Skipping dialing interface '%s' again since it has already been dialed\n", 01756 di->interface); 01757 break; 01758 } 01759 } 01760 AST_LIST_UNLOCK(dialed_interfaces); 01761 01762 if (di) { 01763 fulldial++; 01764 chanlist_free(tmp); 01765 continue; 01766 } 01767 01768 /* It is always ok to dial a Local interface. We only keep track of 01769 * which "real" interfaces have been dialed. The Local channel will 01770 * inherit this list so that if it ends up dialing a real interface, 01771 * it won't call one that has already been called. */ 01772 if (strcasecmp(tech, "Local")) { 01773 if (!(di = ast_calloc(1, sizeof(*di) + strlen(interface)))) { 01774 AST_LIST_UNLOCK(dialed_interfaces); 01775 chanlist_free(tmp); 01776 goto out; 01777 } 01778 strcpy(di->interface, interface); 01779 01780 AST_LIST_LOCK(dialed_interfaces); 01781 AST_LIST_INSERT_TAIL(dialed_interfaces, di, list); 01782 AST_LIST_UNLOCK(dialed_interfaces); 01783 } 01784 01785 tc = ast_request(tech, chan->nativeformats, chan, numsubst, &cause); 01786 if (!tc) { 01787 /* If we can't, just go on to the next call */ 01788 ast_log(LOG_WARNING, "Unable to create channel of type '%s' (cause %d - %s)\n", 01789 tech, cause, ast_cause2str(cause)); 01790 handle_cause(cause, &num); 01791 if (!rest) /* we are on the last destination */ 01792 chan->hangupcause = cause; 01793 chanlist_free(tmp); 01794 continue; 01795 } 01796 pbx_builtin_setvar_helper(tc, "DIALEDPEERNUMBER", numsubst); 01797 01798 ast_channel_lock(tc); 01799 while (ast_channel_trylock(chan)) { 01800 CHANNEL_DEADLOCK_AVOIDANCE(tc); 01801 } 01802 /* Setup outgoing SDP to match incoming one */ 01803 if (!outgoing && !rest && CAN_EARLY_BRIDGE(peerflags, chan, tc)) { 01804 ast_rtp_instance_early_bridge_make_compatible(tc, chan); 01805 } 01806 01807 /* Inherit specially named variables from parent channel */ 01808 ast_channel_inherit_variables(chan, tc); 01809 ast_channel_datastore_inherit(chan, tc); 01810 01811 tc->appl = "AppDial"; 01812 tc->data = "(Outgoing Line)"; 01813 memset(&tc->whentohangup, 0, sizeof(tc->whentohangup)); 01814 01815 /* If the new channel has no callerid, try to guess what it should be */ 01816 if (ast_strlen_zero(tc->cid.cid_num)) { 01817 if (!ast_strlen_zero(chan->connected.id.number)) { 01818 ast_set_callerid(tc, chan->connected.id.number, chan->connected.id.name, chan->connected.ani); 01819 } else if (!ast_strlen_zero(chan->cid.cid_dnid)) { 01820 ast_set_callerid(tc, chan->cid.cid_dnid, NULL, NULL); 01821 } else if (!ast_strlen_zero(S_OR(chan->macroexten, chan->exten))) { 01822 ast_set_callerid(tc, S_OR(chan->macroexten, chan->exten), NULL, NULL); 01823 } 01824 ast_set_flag64(tmp, DIAL_NOCONNECTEDLINE); 01825 } 01826 01827 ast_connected_line_copy_from_caller(&tc->connected, &chan->cid); 01828 01829 S_REPLACE(tc->cid.cid_rdnis, ast_strdup(chan->cid.cid_rdnis)); 01830 ast_party_redirecting_copy(&tc->redirecting, &chan->redirecting); 01831 01832 tc->cid.cid_tns = chan->cid.cid_tns; 01833 01834 if (!ast_strlen_zero(chan->accountcode)) { 01835 ast_string_field_set(tc, peeraccount, chan->accountcode); 01836 } 01837 tc->cdrflags = chan->cdrflags; 01838 if (ast_strlen_zero(tc->musicclass)) 01839 ast_string_field_set(tc, musicclass, chan->musicclass); 01840 01841 /* Pass ADSI CPE and transfer capability */ 01842 tc->adsicpe = chan->adsicpe; 01843 tc->transfercapability = chan->transfercapability; 01844 01845 /* If we have an outbound group, set this peer channel to it */ 01846 if (outbound_group) 01847 ast_app_group_set_channel(tc, outbound_group); 01848 /* If the calling channel has the ANSWERED_ELSEWHERE flag set, inherit it. This is to support local channels */ 01849 if (ast_test_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE)) 01850 ast_set_flag(tc, AST_FLAG_ANSWERED_ELSEWHERE); 01851 01852 /* Check if we're forced by configuration */ 01853 if (ast_test_flag64(&opts, OPT_CANCEL_ELSEWHERE)) 01854 ast_set_flag(tc, AST_FLAG_ANSWERED_ELSEWHERE); 01855 01856 01857 /* Inherit context and extension */ 01858 ast_string_field_set(tc, dialcontext, ast_strlen_zero(chan->macrocontext) ? chan->context : chan->macrocontext); 01859 if (!ast_strlen_zero(chan->macroexten)) 01860 ast_copy_string(tc->exten, chan->macroexten, sizeof(tc->exten)); 01861 else 01862 ast_copy_string(tc->exten, chan->exten, sizeof(tc->exten)); 01863 01864 ast_channel_unlock(tc); 01865 res = ast_call(tc, numsubst, 0); /* Place the call, but don't wait on the answer */ 01866 01867 /* Save the info in cdr's that we called them */ 01868 if (chan->cdr) 01869 ast_cdr_setdestchan(chan->cdr, tc->name); 01870 01871 /* check the results of ast_call */ 01872 if (res) { 01873 /* Again, keep going even if there's an error */ 01874 ast_debug(1, "ast call on peer returned %d\n", res); 01875 ast_verb(3, "Couldn't call %s\n", numsubst); 01876 if (tc->hangupcause) { 01877 chan->hangupcause = tc->hangupcause; 01878 } 01879 ast_channel_unlock(chan); 01880 ast_hangup(tc); 01881 tc = NULL; 01882 chanlist_free(tmp); 01883 continue; 01884 } else { 01885 const char *tmpexten = ast_strdupa(S_OR(chan->macroexten, chan->exten)); 01886 senddialevent(chan, tc, numsubst); 01887 ast_verb(3, "Called %s\n", numsubst); 01888 ast_channel_unlock(chan); 01889 if (!ast_test_flag64(peerflags, OPT_ORIGINAL_CLID)) { 01890 ast_set_callerid(tc, tmpexten, get_cid_name(cidname, sizeof(cidname), chan), NULL); 01891 } 01892 } 01893 /* Put them in the list of outgoing thingies... We're ready now. 01894 XXX If we're forcibly removed, these outgoing calls won't get 01895 hung up XXX */ 01896 ast_set_flag64(tmp, DIAL_STILLGOING); 01897 tmp->chan = tc; 01898 tmp->next = outgoing; 01899 outgoing = tmp; 01900 /* If this line is up, don't try anybody else */ 01901 if (outgoing->chan->_state == AST_STATE_UP) 01902 break; 01903 } 01904 01905 if (ast_strlen_zero(args.timeout)) { 01906 to = -1; 01907 } else { 01908 to = atoi(args.timeout); 01909 if (to > 0) 01910 to *= 1000; 01911 else { 01912 ast_log(LOG_WARNING, "Invalid timeout specified: '%s'. Setting timeout to infinite\n", args.timeout); 01913 to = -1; 01914 } 01915 } 01916 01917 if (!outgoing) { 01918 strcpy(pa.status, "CHANUNAVAIL"); 01919 if (fulldial == num_dialed) { 01920 res = -1; 01921 goto out; 01922 } 01923 } else { 01924 /* Our status will at least be NOANSWER */ 01925 strcpy(pa.status, "NOANSWER"); 01926 if (ast_test_flag64(outgoing, OPT_MUSICBACK)) { 01927 moh = 1; 01928 if (!ast_strlen_zero(opt_args[OPT_ARG_MUSICBACK])) { 01929 char *original_moh = ast_strdupa(chan->musicclass); 01930 ast_string_field_set(chan, musicclass, opt_args[OPT_ARG_MUSICBACK]); 01931 ast_moh_start(chan, opt_args[OPT_ARG_MUSICBACK], NULL); 01932 ast_string_field_set(chan, musicclass, original_moh); 01933 } else { 01934 ast_moh_start(chan, NULL, NULL); 01935 } 01936 ast_indicate(chan, AST_CONTROL_PROGRESS); 01937 } else if (ast_test_flag64(outgoing, OPT_RINGBACK)) { 01938 ast_indicate(chan, AST_CONTROL_RINGING); 01939 sentringing++; 01940 } 01941 } 01942 01943 peer = wait_for_answer(chan, outgoing, &to, peerflags, &pa, &num, &result, dtmf_progress); 01944 01945 /* The ast_channel_datastore_remove() function could fail here if the 01946 * datastore was moved to another channel during a masquerade. If this is 01947 * the case, don't free the datastore here because later, when the channel 01948 * to which the datastore was moved hangs up, it will attempt to free this 01949 * datastore again, causing a crash 01950 */ 01951 if (!ast_channel_datastore_remove(chan, datastore)) 01952 ast_datastore_free(datastore); 01953 if (!peer) { 01954 if (result) { 01955 res = result; 01956 } else if (to) { /* Musta gotten hung up */ 01957 res = -1; 01958 } else { /* Nobody answered, next please? */ 01959 res = 0; 01960 } 01961 01962 /* SIP, in particular, sends back this error code to indicate an 01963 * overlap dialled number needs more digits. */ 01964 if (chan->hangupcause == AST_CAUSE_INVALID_NUMBER_FORMAT) { 01965 res = AST_PBX_INCOMPLETE; 01966 } 01967 01968 /* almost done, although the 'else' block is 400 lines */ 01969 } else { 01970 const char *number; 01971 01972 strcpy(pa.status, "ANSWER"); 01973 pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status); 01974 /* Ah ha! Someone answered within the desired timeframe. Of course after this 01975 we will always return with -1 so that it is hung up properly after the 01976 conversation. */ 01977 hanguptree(outgoing, peer, 1); 01978 outgoing = NULL; 01979 /* If appropriate, log that we have a destination channel */ 01980 if (chan->cdr) 01981 ast_cdr_setdestchan(chan->cdr, peer->name); 01982 if (peer->name) 01983 pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", peer->name); 01984 01985 ast_channel_lock(peer); 01986 number = pbx_builtin_getvar_helper(peer, "DIALEDPEERNUMBER"); 01987 if (!number) 01988 number = numsubst; 01989 pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", number); 01990 ast_channel_unlock(peer); 01991 01992 if (!ast_strlen_zero(args.url) && ast_channel_supports_html(peer) ) { 01993 ast_debug(1, "app_dial: sendurl=%s.\n", args.url); 01994 ast_channel_sendurl( peer, args.url ); 01995 } 01996 if ( (ast_test_flag64(&opts, OPT_PRIVACY) || ast_test_flag64(&opts, OPT_SCREENING)) && pa.privdb_val == AST_PRIVACY_UNKNOWN) { 01997 if (do_privacy(chan, peer, &opts, opt_args, &pa)) { 01998 res = 0; 01999 goto out; 02000 } 02001 } 02002 if (!ast_test_flag64(&opts, OPT_ANNOUNCE) || ast_strlen_zero(opt_args[OPT_ARG_ANNOUNCE])) { 02003 res = 0; 02004 } else { 02005 int digit = 0; 02006 /* Start autoservice on the other chan */ 02007 res = ast_autoservice_start(chan); 02008 /* Now Stream the File */ 02009 if (!res) 02010 res = ast_streamfile(peer, opt_args[OPT_ARG_ANNOUNCE], peer->language); 02011 if (!res) { 02012 digit = ast_waitstream(peer, AST_DIGIT_ANY); 02013 } 02014 /* Ok, done. stop autoservice */ 02015 res = ast_autoservice_stop(chan); 02016 if (digit > 0 && !res) 02017 res = ast_senddigit(chan, digit, 0); 02018 else 02019 res = digit; 02020 02021 } 02022 02023 if (chan && peer && ast_test_flag64(&opts, OPT_GOTO) && !ast_strlen_zero(opt_args[OPT_ARG_GOTO])) { 02024 replace_macro_delimiter(opt_args[OPT_ARG_GOTO]); 02025 ast_parseable_goto(chan, opt_args[OPT_ARG_GOTO]); 02026 /* peer goes to the same context and extension as chan, so just copy info from chan*/ 02027 ast_copy_string(peer->context, chan->context, sizeof(peer->context)); 02028 ast_copy_string(peer->exten, chan->exten, sizeof(peer->exten)); 02029 peer->priority = chan->priority + 2; 02030 ast_pbx_start(peer); 02031 hanguptree(outgoing, NULL, ast_test_flag64(&opts, OPT_CANCEL_ELSEWHERE) ? 1 : 0); 02032 if (continue_exec) 02033 *continue_exec = 1; 02034 res = 0; 02035 goto done; 02036 } 02037 02038 if (ast_test_flag64(&opts, OPT_CALLEE_MACRO) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_MACRO])) { 02039 struct ast_app *theapp; 02040 const char *macro_result; 02041 02042 res = ast_autoservice_start(chan); 02043 if (res) { 02044 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n"); 02045 res = -1; 02046 } 02047 02048 theapp = pbx_findapp("Macro"); 02049 02050 if (theapp && !res) { /* XXX why check res here ? */ 02051 /* Set peer->exten and peer->context so that MACRO_EXTEN and MACRO_CONTEXT get set */ 02052 ast_copy_string(peer->context, chan->context, sizeof(peer->context)); 02053 ast_copy_string(peer->exten, chan->exten, sizeof(peer->exten)); 02054 02055 replace_macro_delimiter(opt_args[OPT_ARG_CALLEE_MACRO]); 02056 res = pbx_exec(peer, theapp, opt_args[OPT_ARG_CALLEE_MACRO]); 02057 ast_debug(1, "Macro exited with status %d\n", res); 02058 res = 0; 02059 } else { 02060 ast_log(LOG_ERROR, "Could not find application Macro\n"); 02061 res = -1; 02062 } 02063 02064 if (ast_autoservice_stop(chan) < 0) { 02065 res = -1; 02066 } 02067 02068 ast_channel_lock(peer); 02069 02070 if (!res && (macro_result = pbx_builtin_getvar_helper(peer, "MACRO_RESULT"))) { 02071 char *macro_transfer_dest; 02072 02073 if (!strcasecmp(macro_result, "BUSY")) { 02074 ast_copy_string(pa.status, macro_result, sizeof(pa.status)); 02075 ast_set_flag64(peerflags, OPT_GO_ON); 02076 res = -1; 02077 } else if (!strcasecmp(macro_result, "CONGESTION") || !strcasecmp(macro_result, "CHANUNAVAIL")) { 02078 ast_copy_string(pa.status, macro_result, sizeof(pa.status)); 02079 ast_set_flag64(peerflags, OPT_GO_ON); 02080 res = -1; 02081 } else if (!strcasecmp(macro_result, "CONTINUE")) { 02082 /* hangup peer and keep chan alive assuming the macro has changed 02083 the context / exten / priority or perhaps 02084 the next priority in the current exten is desired. 02085 */ 02086 ast_set_flag64(peerflags, OPT_GO_ON); 02087 res = -1; 02088 } else if (!strcasecmp(macro_result, "ABORT")) { 02089 /* Hangup both ends unless the caller has the g flag */ 02090 res = -1; 02091 } else if (!strncasecmp(macro_result, "GOTO:", 5) && (macro_transfer_dest = ast_strdupa(macro_result + 5))) { 02092 res = -1; 02093 /* perform a transfer to a new extension */ 02094 if (strchr(macro_transfer_dest, '^')) { /* context^exten^priority*/ 02095 replace_macro_delimiter(macro_transfer_dest); 02096 if (!ast_parseable_goto(chan, macro_transfer_dest)) 02097 ast_set_flag64(peerflags, OPT_GO_ON); 02098 } 02099 } 02100 } 02101 02102 ast_channel_unlock(peer); 02103 } 02104 02105 if (ast_test_flag64(&opts, OPT_CALLEE_GOSUB) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GOSUB])) { 02106 struct ast_app *theapp; 02107 const char *gosub_result; 02108 char *gosub_args, *gosub_argstart; 02109 int res9 = -1; 02110 02111 res9 = ast_autoservice_start(chan); 02112 if (res9) { 02113 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n"); 02114 res9 = -1; 02115 } 02116 02117 theapp = pbx_findapp("Gosub"); 02118 02119 if (theapp && !res9) { 02120 replace_macro_delimiter(opt_args[OPT_ARG_CALLEE_GOSUB]); 02121 02122 /* Set where we came from */ 02123 ast_copy_string(peer->context, "app_dial_gosub_virtual_context", sizeof(peer->context)); 02124 ast_copy_string(peer->exten, "s", sizeof(peer->exten)); 02125 peer->priority = 0; 02126 02127 gosub_argstart = strchr(opt_args[OPT_ARG_CALLEE_GOSUB], ','); 02128 if (gosub_argstart) { 02129 *gosub_argstart = 0; 02130 if (asprintf(&gosub_args, "%s,s,1(%s)", opt_args[OPT_ARG_CALLEE_GOSUB], gosub_argstart + 1) < 0) { 02131 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 02132 gosub_args = NULL; 02133 } 02134 *gosub_argstart = ','; 02135 } else { 02136 if (asprintf(&gosub_args, "%s,s,1", opt_args[OPT_ARG_CALLEE_GOSUB]) < 0) { 02137 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 02138 gosub_args = NULL; 02139 } 02140 } 02141 02142 if (gosub_args) { 02143 res9 = pbx_exec(peer, theapp, gosub_args); 02144 if (!res9) { 02145 struct ast_pbx_args args; 02146 /* A struct initializer fails to compile for this case ... */ 02147 memset(&args, 0, sizeof(args)); 02148 args.no_hangup_chan = 1; 02149 ast_pbx_run_args(peer, &args); 02150 } 02151 ast_free(gosub_args); 02152 ast_debug(1, "Gosub exited with status %d\n", res9); 02153 } else { 02154 ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n"); 02155 } 02156 02157 } else if (!res9) { 02158 ast_log(LOG_ERROR, "Could not find application Gosub\n"); 02159 res9 = -1; 02160 } 02161 02162 if (ast_autoservice_stop(chan) < 0) { 02163 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n"); 02164 res9 = -1; 02165 } 02166 02167 ast_channel_lock(peer); 02168 02169 if (!res9 && (gosub_result = pbx_builtin_getvar_helper(peer, "GOSUB_RESULT"))) { 02170 char *gosub_transfer_dest; 02171 02172 if (!strcasecmp(gosub_result, "BUSY")) { 02173 ast_copy_string(pa.status, gosub_result, sizeof(pa.status)); 02174 ast_set_flag64(peerflags, OPT_GO_ON); 02175 res9 = -1; 02176 } else if (!strcasecmp(gosub_result, "CONGESTION") || !strcasecmp(gosub_result, "CHANUNAVAIL")) { 02177 ast_copy_string(pa.status, gosub_result, sizeof(pa.status)); 02178 ast_set_flag64(peerflags, OPT_GO_ON); 02179 res9 = -1; 02180 } else if (!strcasecmp(gosub_result, "CONTINUE")) { 02181 /* hangup peer and keep chan alive assuming the macro has changed 02182 the context / exten / priority or perhaps 02183 the next priority in the current exten is desired. 02184 */ 02185 ast_set_flag64(peerflags, OPT_GO_ON); 02186 res9 = -1; 02187 } else if (!strcasecmp(gosub_result, "ABORT")) { 02188 /* Hangup both ends unless the caller has the g flag */ 02189 res9 = -1; 02190 } else if (!strncasecmp(gosub_result, "GOTO:", 5) && (gosub_transfer_dest = ast_strdupa(gosub_result + 5))) { 02191 res9 = -1; 02192 /* perform a transfer to a new extension */ 02193 if (strchr(gosub_transfer_dest, '^')) { /* context^exten^priority*/ 02194 replace_macro_delimiter(gosub_transfer_dest); 02195 if (!ast_parseable_goto(chan, gosub_transfer_dest)) 02196 ast_set_flag64(peerflags, OPT_GO_ON); 02197 } 02198 } 02199 } 02200 02201 ast_channel_unlock(peer); 02202 } 02203 02204 if (!res) { 02205 if (!ast_tvzero(calldurationlimit)) { 02206 struct timeval whentohangup = calldurationlimit; 02207 peer->whentohangup = ast_tvadd(ast_tvnow(), whentohangup); 02208 } 02209 if (!ast_strlen_zero(dtmfcalled)) { 02210 ast_verb(3, "Sending DTMF '%s' to the called party.\n", dtmfcalled); 02211 res = ast_dtmf_stream(peer, chan, dtmfcalled, 250, 0); 02212 } 02213 if (!ast_strlen_zero(dtmfcalling)) { 02214 ast_verb(3, "Sending DTMF '%s' to the calling party.\n", dtmfcalling); 02215 res = ast_dtmf_stream(chan, peer, dtmfcalling, 250, 0); 02216 } 02217 } 02218 02219 if (res) { /* some error */ 02220 res = -1; 02221 } else { 02222 if (ast_test_flag64(peerflags, OPT_CALLEE_TRANSFER)) 02223 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); 02224 if (ast_test_flag64(peerflags, OPT_CALLER_TRANSFER)) 02225 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); 02226 if (ast_test_flag64(peerflags, OPT_CALLEE_HANGUP)) 02227 ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT); 02228 if (ast_test_flag64(peerflags, OPT_CALLER_HANGUP)) 02229 ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT); 02230 if (ast_test_flag64(peerflags, OPT_CALLEE_MONITOR)) 02231 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON); 02232 if (ast_test_flag64(peerflags, OPT_CALLER_MONITOR)) 02233 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON); 02234 if (ast_test_flag64(peerflags, OPT_CALLEE_PARK)) 02235 ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL); 02236 if (ast_test_flag64(peerflags, OPT_CALLER_PARK)) 02237 ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL); 02238 if (ast_test_flag64(peerflags, OPT_CALLEE_MIXMONITOR)) 02239 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMIXMON); 02240 if (ast_test_flag64(peerflags, OPT_CALLER_MIXMONITOR)) 02241 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMIXMON); 02242 if (ast_test_flag64(peerflags, OPT_GO_ON)) 02243 ast_set_flag(&(config.features_caller), AST_FEATURE_NO_H_EXTEN); 02244 02245 config.end_bridge_callback = end_bridge_callback; 02246 config.end_bridge_callback_data = chan; 02247 config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup; 02248 02249 if (moh) { 02250 moh = 0; 02251 ast_moh_stop(chan); 02252 } else if (sentringing) { 02253 sentringing = 0; 02254 ast_indicate(chan, -1); 02255 } 02256 /* Be sure no generators are left on it */ 02257 ast_deactivate_generator(chan); 02258 /* Make sure channels are compatible */ 02259 res = ast_channel_make_compatible(chan, peer); 02260 if (res < 0) { 02261 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", chan->name, peer->name); 02262 ast_hangup(peer); 02263 res = -1; 02264 goto done; 02265 } 02266 if (opermode) { 02267 struct oprmode oprmode; 02268 02269 oprmode.peer = peer; 02270 oprmode.mode = opermode; 02271 02272 ast_channel_setoption(chan, AST_OPTION_OPRMODE, &oprmode, sizeof(oprmode), 0); 02273 } 02274 res = ast_bridge_call(chan, peer, &config); 02275 } 02276 02277 strcpy(peer->context, chan->context); 02278 02279 if (ast_test_flag64(&opts, OPT_PEER_H) && ast_exists_extension(peer, peer->context, "h", 1, peer->cid.cid_num)) { 02280 int autoloopflag; 02281 int found; 02282 int res9; 02283 02284 strcpy(peer->exten, "h"); 02285 peer->priority = 1; 02286 autoloopflag = ast_test_flag(peer, AST_FLAG_IN_AUTOLOOP); /* save value to restore at the end */ 02287 ast_set_flag(peer, AST_FLAG_IN_AUTOLOOP); 02288 02289 while ((res9 = ast_spawn_extension(peer, peer->context, peer->exten, peer->priority, peer->cid.cid_num, &found, 1)) == 0) 02290 peer->priority++; 02291 02292 if (found && res9) { 02293 /* Something bad happened, or a hangup has been requested. */ 02294 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", peer->context, peer->exten, peer->priority, peer->name); 02295 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", peer->context, peer->exten, peer->priority, peer->name); 02296 } 02297 ast_set2_flag(peer, autoloopflag, AST_FLAG_IN_AUTOLOOP); /* set it back the way it was */ 02298 } 02299 if (!ast_check_hangup(peer) && ast_test_flag64(&opts, OPT_CALLEE_GO_ON)) { 02300 if(!ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GO_ON])) { 02301 replace_macro_delimiter(opt_args[OPT_ARG_CALLEE_GO_ON]); 02302 ast_parseable_goto(peer, opt_args[OPT_ARG_CALLEE_GO_ON]); 02303 } else { /* F() */ 02304 int res; 02305 res = ast_goto_if_exists(peer, chan->context, chan->exten, (chan->priority) + 1); 02306 if (res == AST_PBX_GOTO_FAILED) { 02307 ast_hangup(peer); 02308 goto out; 02309 } 02310 } 02311 ast_pbx_start(peer); 02312 } else { 02313 if (!ast_check_hangup(chan)) 02314 chan->hangupcause = peer->hangupcause; 02315 ast_hangup(peer); 02316 } 02317 } 02318 out: 02319 if (moh) { 02320 moh = 0; 02321 ast_moh_stop(chan); 02322 } else if (sentringing) { 02323 sentringing = 0; 02324 ast_indicate(chan, -1); 02325 } 02326 ast_channel_early_bridge(chan, NULL); 02327 hanguptree(outgoing, NULL, 0); /* In this case, there's no answer anywhere */ 02328 pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status); 02329 senddialendevent(chan, pa.status); 02330 ast_debug(1, "Exiting with DIALSTATUS=%s.\n", pa.status); 02331 02332 if ((ast_test_flag64(peerflags, OPT_GO_ON)) && !ast_check_hangup(chan) && (res != AST_PBX_INCOMPLETE)) { 02333 if (!ast_tvzero(calldurationlimit)) 02334 memset(&chan->whentohangup, 0, sizeof(chan->whentohangup)); 02335 res = 0; 02336 } 02337 02338 done: 02339 if (config.warning_sound) { 02340 ast_free((char *)config.warning_sound); 02341 } 02342 if (config.end_sound) { 02343 ast_free((char *)config.end_sound); 02344 } 02345 if (config.start_sound) { 02346 ast_free((char *)config.start_sound); 02347 } 02348 return res; 02349 }
| static void do_forward | ( | struct chanlist * | o, | |
| struct cause_args * | num, | |||
| struct ast_flags64 * | peerflags, | |||
| int | single, | |||
| int * | to | |||
| ) | [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 738 of file app_dial.c.
References ast_channel::accountcode, accountcode, ast_call(), AST_CAUSE_BUSY, AST_CEL_FORWARD, ast_cel_report_event(), ast_channel_datastore_inherit(), ast_channel_inherit_variables(), ast_channel_lock, ast_channel_make_compatible(), ast_channel_set_redirecting(), ast_channel_trylock, ast_channel_unlock, ast_channel_update_redirecting(), ast_clear_flag64, ast_copy_string(), ast_hangup(), ast_indicate(), ast_log(), AST_MAX_EXTENSION, ast_party_caller_copy(), ast_party_connected_line_copy(), ast_request(), ast_rtp_instance_early_bridge_make_compatible(), ast_set_callerid(), ast_strdup, ast_strdupa, ast_string_field_set, ast_strlen_zero(), ast_test_flag64, ast_verb, ast_channel::call_forward, CAN_EARLY_BRIDGE, cause, ast_channel::cdrflags, cause_args::chan, chanlist::chan, CHANNEL_DEADLOCK_AVOIDANCE, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, ast_callerid::cid_rdnis, ast_callerid::cid_tns, ast_channel::connected, ast_channel::context, DIAL_STILLGOING, ast_channel::exten, get_cid_name(), handle_cause(), LOG_NOTICE, ast_channel::macroexten, ast_channel::name, ast_channel::nativeformats, cause_args::nochan, OPT_CANCEL_TIMEOUT, OPT_FORCECLID, OPT_IGNORE_CONNECTEDLINE, OPT_IGNORE_FORWARDING, OPT_ORIGINAL_CLID, pbx_builtin_getvar_helper(), ast_channel::redirecting, S_OR, S_REPLACE, and senddialevent().
Referenced by wait_for_answer().
00740 { 00741 char tmpchan[256]; 00742 struct ast_channel *original = o->chan; 00743 struct ast_channel *c = o->chan; /* the winner */ 00744 struct ast_channel *in = num->chan; /* the input channel */ 00745 struct ast_party_redirecting *apr = &o->chan->redirecting; 00746 struct ast_party_connected_line *apc = &o->chan->connected; 00747 char *stuff; 00748 char *tech; 00749 int cause; 00750 00751 ast_copy_string(tmpchan, c->call_forward, sizeof(tmpchan)); 00752 if ((stuff = strchr(tmpchan, '/'))) { 00753 *stuff++ = '\0'; 00754 tech = tmpchan; 00755 } else { 00756 const char *forward_context; 00757 ast_channel_lock(c); 00758 forward_context = pbx_builtin_getvar_helper(c, "FORWARD_CONTEXT"); 00759 if (ast_strlen_zero(forward_context)) { 00760 forward_context = NULL; 00761 } 00762 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", c->call_forward, forward_context ? forward_context : c->context); 00763 ast_channel_unlock(c); 00764 stuff = tmpchan; 00765 tech = "Local"; 00766 } 00767 00768 ast_cel_report_event(in, AST_CEL_FORWARD, NULL, c->call_forward, NULL); 00769 00770 /* Before processing channel, go ahead and check for forwarding */ 00771 ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, c->name); 00772 /* If we have been told to ignore forwards, just set this channel to null and continue processing extensions normally */ 00773 if (ast_test_flag64(peerflags, OPT_IGNORE_FORWARDING)) { 00774 ast_verb(3, "Forwarding %s to '%s/%s' prevented.\n", in->name, tech, stuff); 00775 c = o->chan = NULL; 00776 cause = AST_CAUSE_BUSY; 00777 } else { 00778 /* Setup parameters */ 00779 c = o->chan = ast_request(tech, in->nativeformats, in, stuff, &cause); 00780 if (c) { 00781 if (single) 00782 ast_channel_make_compatible(o->chan, in); 00783 ast_channel_inherit_variables(in, o->chan); 00784 ast_channel_datastore_inherit(in, o->chan); 00785 } else 00786 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause); 00787 } 00788 if (!c) { 00789 ast_clear_flag64(o, DIAL_STILLGOING); 00790 handle_cause(cause, num); 00791 ast_hangup(original); 00792 } else { 00793 if (single && CAN_EARLY_BRIDGE(peerflags, c, in)) { 00794 ast_rtp_instance_early_bridge_make_compatible(c, in); 00795 } 00796 00797 c->cdrflags = in->cdrflags; 00798 00799 ast_channel_set_redirecting(c, apr); 00800 ast_channel_lock(c); 00801 while (ast_channel_trylock(in)) { 00802 CHANNEL_DEADLOCK_AVOIDANCE(c); 00803 } 00804 S_REPLACE(c->cid.cid_rdnis, ast_strdup(S_OR(original->cid.cid_rdnis, S_OR(in->macroexten, in->exten)))); 00805 00806 c->cid.cid_tns = in->cid.cid_tns; 00807 00808 if (ast_test_flag64(o, OPT_FORCECLID)) { 00809 S_REPLACE(c->cid.cid_num, ast_strdupa(S_OR(in->macroexten, in->exten))); 00810 S_REPLACE(c->cid.cid_name, NULL); 00811 ast_string_field_set(c, accountcode, c->accountcode); 00812 } else { 00813 ast_party_caller_copy(&c->cid, &in->cid); 00814 ast_string_field_set(c, accountcode, in->accountcode); 00815 } 00816 ast_party_connected_line_copy(&c->connected, apc); 00817 00818 S_REPLACE(in->cid.cid_rdnis, ast_strdup(c->cid.cid_rdnis)); 00819 ast_channel_update_redirecting(in, apr); 00820 00821 ast_clear_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE); 00822 if (ast_test_flag64(peerflags, OPT_CANCEL_TIMEOUT)) { 00823 *to = -1; 00824 } 00825 00826 ast_channel_unlock(in); 00827 ast_channel_unlock(c); 00828 00829 if (ast_call(c, tmpchan, 0)) { 00830 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan); 00831 ast_clear_flag64(o, DIAL_STILLGOING); 00832 ast_hangup(original); 00833 ast_hangup(c); 00834 c = o->chan = NULL; 00835 num->nochan++; 00836 } else { 00837 ast_channel_lock(c); 00838 while (ast_channel_trylock(in)) { 00839 CHANNEL_DEADLOCK_AVOIDANCE(c); 00840 } 00841 senddialevent(in, c, stuff); 00842 if (!ast_test_flag64(peerflags, OPT_ORIGINAL_CLID)) { 00843 char cidname[AST_MAX_EXTENSION] = ""; 00844 const char *tmpexten; 00845 tmpexten = ast_strdupa(S_OR(in->macroexten, in->exten)); 00846 ast_channel_unlock(in); 00847 ast_channel_unlock(c); 00848 ast_set_callerid(c, tmpexten, get_cid_name(cidname, sizeof(cidname), in), NULL); 00849 } else { 00850 ast_channel_unlock(in); 00851 ast_channel_unlock(c); 00852 } 00853 /* Hangup the original channel now, in case we needed it */ 00854 ast_hangup(original); 00855 } 00856 if (single) { 00857 ast_indicate(in, -1); 00858 } 00859 } 00860 }
| static void end_bridge_callback | ( | void * | data | ) | [static] |
Definition at line 1530 of file app_dial.c.
References ast_cdr::answer, ast_channel_lock, ast_channel_unlock, buf, ast_channel::cdr, pbx_builtin_setvar_helper(), and ast_cdr::start.
Referenced by app_exec(), dial_exec_full(), and try_calling().
01531 { 01532 char buf[80]; 01533 time_t end; 01534 struct ast_channel *chan = data; 01535 01536 if (!chan->cdr) { 01537 return; 01538 } 01539 01540 time(&end); 01541 01542 ast_channel_lock(chan); 01543 if (chan->cdr->answer.tv_sec) { 01544 snprintf(buf, sizeof(buf), "%ld", end - chan->cdr->answer.tv_sec); 01545 pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf); 01546 } 01547 01548 if (chan->cdr->start.tv_sec) { 01549 snprintf(buf, sizeof(buf), "%ld", end - chan->cdr->start.tv_sec); 01550 pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf); 01551 } 01552 ast_channel_unlock(chan); 01553 }
| static void end_bridge_callback_data_fixup | ( | struct ast_bridge_config * | bconfig, | |
| struct ast_channel * | originator, | |||
| struct ast_channel * | terminator | |||
| ) | [static] |
Definition at line 1555 of file app_dial.c.
References ast_bridge_config::end_bridge_callback_data.
Referenced by app_exec(), dial_exec_full(), and try_calling().
01555 { 01556 bconfig->end_bridge_callback_data = originator; 01557 }
| static const char* get_cid_name | ( | char * | name, | |
| int | namelen, | |||
| struct ast_channel * | chan | |||
| ) | [static] |
Definition at line 691 of file app_dial.c.
References ast_channel_lock, ast_channel_unlock, ast_get_hint(), ast_strdupa, 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().
00692 { 00693 const char *context; 00694 const char *exten; 00695 00696 ast_channel_lock(chan); 00697 context = ast_strdupa(S_OR(chan->macrocontext, chan->context)); 00698 exten = ast_strdupa(S_OR(chan->macroexten, chan->exten)); 00699 ast_channel_unlock(chan); 00700 00701 return ast_get_hint(NULL, 0, name, namelen, chan, context, exten) ? name : ""; 00702 }
| static void handle_cause | ( | int | cause, | |
| struct cause_args * | num | |||
| ) | [static] |
Definition at line 626 of file app_dial.c.
References AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, AST_CAUSE_NO_ANSWER, AST_CAUSE_NO_ROUTE_DESTINATION, AST_CAUSE_NORMAL_CLEARING, AST_CAUSE_UNREGISTERED, ast_cdr_busy(), ast_cdr_failed(), ast_cdr_noanswer(), cause_args::busy, ast_channel::cdr, cause_args::chan, cause_args::congestion, and cause_args::nochan.
Referenced by __ast_request_and_dial(), ast_call_forward(), dial_exec_full(), do_forward(), and wait_for_answer().
00627 { 00628 struct ast_cdr *cdr = num->chan->cdr; 00629 00630 switch(cause) { 00631 case AST_CAUSE_BUSY: 00632 if (cdr) 00633 ast_cdr_busy(cdr); 00634 num->busy++; 00635 break; 00636 00637 case AST_CAUSE_CONGESTION: 00638 if (cdr) 00639 ast_cdr_failed(cdr); 00640 num->congestion++; 00641 break; 00642 00643 case AST_CAUSE_NO_ROUTE_DESTINATION: 00644 case AST_CAUSE_UNREGISTERED: 00645 if (cdr) 00646 ast_cdr_failed(cdr); 00647 num->nochan++; 00648 break; 00649 00650 case AST_CAUSE_NO_ANSWER: 00651 if (cdr) { 00652 ast_cdr_noanswer(cdr); 00653 } 00654 break; 00655 case AST_CAUSE_NORMAL_CLEARING: 00656 break; 00657 00658 default: 00659 num->nochan++; 00660 break; 00661 } 00662 }
| static void hanguptree | ( | struct chanlist * | outgoing, | |
| struct ast_channel * | exception, | |||
| int | answered_elsewhere | |||
| ) | [static] |
Definition at line 592 of file app_dial.c.
References AST_CAUSE_ANSWERED_ELSEWHERE, AST_FLAG_ANSWERED_ELSEWHERE, ast_hangup(), ast_party_connected_line_free(), ast_set_flag, chanlist::chan, chanlist_free(), chanlist::connected, ast_channel::hangupcause, and chanlist::next.
Referenced by dial_exec_full().
00593 { 00594 /* Hang up a tree of stuff */ 00595 struct chanlist *oo; 00596 while (outgoing) { 00597 /* Hangup any existing lines we have open */ 00598 if (outgoing->chan && (outgoing->chan != exception)) { 00599 if (answered_elsewhere) { 00600 /* The flag is used for local channel inheritance and stuff */ 00601 ast_set_flag(outgoing->chan, AST_FLAG_ANSWERED_ELSEWHERE); 00602 /* This is for the channel drivers */ 00603 outgoing->chan->hangupcause = AST_CAUSE_ANSWERED_ELSEWHERE; 00604 } 00605 ast_party_connected_line_free(&outgoing->connected); 00606 ast_hangup(outgoing->chan); 00607 } 00608 oo = outgoing; 00609 outgoing = outgoing->next; 00610 chanlist_free(oo); 00611 } 00612 }
| static int load_module | ( | void | ) | [static] |
Definition at line 2484 of file app_dial.c.
References ast_add_extension2(), ast_context_find_or_create(), ast_free_ptr, ast_log(), ast_register_application_xml, ast_strdup, dial_exec(), LOG_ERROR, and retrydial_exec().
02485 { 02486 int res; 02487 struct ast_context *con; 02488 02489 con = ast_context_find_or_create(NULL, NULL, "app_dial_gosub_virtual_context", "app_dial"); 02490 if (!con) 02491 ast_log(LOG_ERROR, "Dial virtual context 'app_dial_gosub_virtual_context' does not exist and unable to create\n"); 02492 else 02493 ast_add_extension2(con, 1, "s", 1, NULL, NULL, "NoOp", ast_strdup(""), ast_free_ptr, "app_dial"); 02494 02495 res = ast_register_application_xml(app, dial_exec); 02496 res |= ast_register_application_xml(rapp, retrydial_exec); 02497 02498 return res; 02499 }
| static int onedigit_goto | ( | struct ast_channel * | chan, | |
| const char * | context, | |||
| char | exten, | |||
| int | pri | |||
| ) | [static] |
Definition at line 672 of file app_dial.c.
References ast_goto_if_exists(), ast_strlen_zero(), ast_channel::context, and ast_channel::macrocontext.
Referenced by retrydial_exec(), and wait_for_answer().
00673 { 00674 char rexten[2] = { exten, '\0' }; 00675 00676 if (context) { 00677 if (!ast_goto_if_exists(chan, context, rexten, pri)) 00678 return 1; 00679 } else { 00680 if (!ast_goto_if_exists(chan, chan->context, rexten, pri)) 00681 return 1; 00682 else if (!ast_strlen_zero(chan->macrocontext)) { 00683 if (!ast_goto_if_exists(chan, chan->macrocontext, rexten, pri)) 00684 return 1; 00685 } 00686 } 00687 return 0; 00688 }
| static void replace_macro_delimiter | ( | char * | s | ) | [static] |
| static int retrydial_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
Definition at line 2360 of file app_dial.c.
References AST_APP_ARG, ast_channel_lock, ast_channel_unlock, AST_DECLARE_APP_ARGS, AST_DIGIT_ANY, ast_fileexists(), AST_FLAG_MOH, ast_log(), ast_moh_start(), ast_moh_stop(), AST_PBX_INCOMPLETE, AST_STANDARD_APP_ARGS, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_test_flag64, ast_waitfordigit(), ast_waitstream(), context, ast_channel::data, dial_exec_full(), ast_channel::language, LOG_ERROR, LOG_WARNING, onedigit_goto(), OPT_DTMF_EXIT, parse(), and pbx_builtin_getvar_helper().
Referenced by load_module().
02361 { 02362 char *parse; 02363 const char *context = NULL; 02364 int sleepms = 0, loops = 0, res = -1; 02365 struct ast_flags64 peerflags = { 0, }; 02366 AST_DECLARE_APP_ARGS(args, 02367 AST_APP_ARG(announce); 02368 AST_APP_ARG(sleep); 02369 AST_APP_ARG(retries); 02370 AST_APP_ARG(dialdata); 02371 ); 02372 02373 if (ast_strlen_zero(data)) { 02374 ast_log(LOG_WARNING, "RetryDial requires an argument!\n"); 02375 return -1; 02376 } 02377 02378 parse = ast_strdupa(data); 02379 AST_STANDARD_APP_ARGS(args, parse); 02380 02381 if (!ast_strlen_zero(args.sleep) && (sleepms = atoi(args.sleep))) 02382 sleepms *= 1000; 02383 02384 if (!ast_strlen_zero(args.retries)) { 02385 loops = atoi(args.retries); 02386 } 02387 02388 if (!args.dialdata) { 02389 ast_log(LOG_ERROR, "%s requires a 4th argument (dialdata)\n", rapp); 02390 goto done; 02391 } 02392 02393 if (sleepms < 1000) 02394 sleepms = 10000; 02395 02396 if (!loops) 02397 loops = -1; /* run forever */ 02398 02399 ast_channel_lock(chan); 02400 context = pbx_builtin_getvar_helper(chan, "EXITCONTEXT"); 02401 context = !ast_strlen_zero(context) ? ast_strdupa(context) : NULL; 02402 ast_channel_unlock(chan); 02403 02404 res = 0; 02405 while (loops) { 02406 int continue_exec; 02407 02408 chan->data = "Retrying"; 02409 if (ast_test_flag(chan, AST_FLAG_MOH)) 02410 ast_moh_stop(chan); 02411 02412 res = dial_exec_full(chan, args.dialdata, &peerflags, &continue_exec); 02413 if (continue_exec) 02414 break; 02415 02416 if (res == 0) { 02417 if (ast_test_flag64(&peerflags, OPT_DTMF_EXIT)) { 02418 if (!ast_strlen_zero(args.announce)) { 02419 if (ast_fileexists(args.announce, NULL, chan->language) > 0) { 02420 if (!(res = ast_streamfile(chan, args.announce, chan->language))) 02421 ast_waitstream(chan, AST_DIGIT_ANY); 02422 } else 02423 ast_log(LOG_WARNING, "Announce file \"%s\" specified in Retrydial does not exist\n", args.announce); 02424 } 02425 if (!res && sleepms) { 02426 if (!ast_test_flag(chan, AST_FLAG_MOH)) 02427 ast_moh_start(chan, NULL, NULL); 02428 res = ast_waitfordigit(chan, sleepms); 02429 } 02430 } else { 02431 if (!ast_strlen_zero(args.announce)) { 02432 if (ast_fileexists(args.announce, NULL, chan->language) > 0) { 02433 if (!(res = ast_streamfile(chan, args.announce, chan->language))) 02434 res = ast_waitstream(chan, ""); 02435 } else 02436 ast_log(LOG_WARNING, "Announce file \"%s\" specified in Retrydial does not exist\n", args.announce); 02437 } 02438 if (sleepms) { 02439 if (!ast_test_flag(chan, AST_FLAG_MOH)) 02440 ast_moh_start(chan, NULL, NULL); 02441 if (!res) 02442 res = ast_waitfordigit(chan, sleepms); 02443 } 02444 } 02445 } 02446 02447 if (res < 0 || res == AST_PBX_INCOMPLETE) { 02448 break; 02449 } else if (res > 0) { /* Trying to send the call elsewhere (1 digit ext) */ 02450 if (onedigit_goto(chan, context, (char) res, 1)) { 02451 res = 0; 02452 break; 02453 } 02454 } 02455 loops--; 02456 } 02457 if (loops == 0) 02458 res = 0; 02459 else if (res == 1) 02460 res = 0; 02461 02462 if (ast_test_flag(chan, AST_FLAG_MOH)) 02463 ast_moh_stop(chan); 02464 done: 02465 return res; 02466 }
| static void senddialendevent | ( | const struct ast_channel * | src, | |
| const char * | dialstatus | |||
| ) | [static] |
Definition at line 720 of file app_dial.c.
References EVENT_FLAG_CALL, manager_event, ast_channel::name, and ast_channel::uniqueid.
Referenced by dial_exec_full().
00721 { 00722 manager_event(EVENT_FLAG_CALL, "Dial", 00723 "SubEvent: End\r\n" 00724 "Channel: %s\r\n" 00725 "UniqueID: %s\r\n" 00726 "DialStatus: %s\r\n", 00727 src->name, src->uniqueid, dialstatus); 00728 }
| static void senddialevent | ( | struct ast_channel * | src, | |
| struct ast_channel * | dst, | |||
| const char * | dialstring | |||
| ) | [static] |
Definition at line 704 of file app_dial.c.
References ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, EVENT_FLAG_CALL, manager_event, ast_channel::name, S_OR, and ast_channel::uniqueid.
Referenced by dial_exec_full(), and do_forward().
00705 { 00706 manager_event(EVENT_FLAG_CALL, "Dial", 00707 "SubEvent: Begin\r\n" 00708 "Channel: %s\r\n" 00709 "Destination: %s\r\n" 00710 "CallerIDNum: %s\r\n" 00711 "CallerIDName: %s\r\n" 00712 "UniqueID: %s\r\n" 00713 "DestUniqueID: %s\r\n" 00714 "Dialstring: %s\r\n", 00715 src->name, dst->name, S_OR(src->cid.cid_num, "<unknown>"), 00716 S_OR(src->cid.cid_name, "<unknown>"), src->uniqueid, 00717 dst->uniqueid, dialstring ? dialstring : ""); 00718 }
| 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 1429 of file app_dial.c.
References ast_answer(), ast_config_AST_DATA_DIR, ast_copy_string(), ast_dsp_get_threshold_from_settings(), ast_filedelete(), ast_fileexists(), ast_log(), ast_mkdir(), ast_play_and_record(), AST_PRIVACY_ALLOW, ast_privacy_check(), AST_PRIVACY_DENY, AST_PRIVACY_KILL, AST_PRIVACY_TORTURE, AST_PRIVACY_UNKNOWN, ast_shrink_phone_number(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag64, ast_verb, ast_waitstream(), ast_channel::cid, ast_callerid::cid_num, ast_channel::exten, ast_channel::language, LOG_NOTICE, LOG_WARNING, ast_channel::name, OPT_ARG_PRIVACY, OPT_PRIVACY, OPT_SCREEN_NOCALLERID, privacy_args::privcid, privacy_args::privdb_val, privacy_args::privintro, silencethreshold, privacy_args::status, and THRESHOLD_SILENCE.
Referenced by dial_exec_full().
01431 { 01432 char callerid[60]; 01433 int res; 01434 char *l; 01435 int silencethreshold; 01436 01437 if (!ast_strlen_zero(chan->cid.cid_num)) { 01438 l = ast_strdupa(chan->cid.cid_num); 01439 ast_shrink_phone_number(l); 01440 if (ast_test_flag64(opts, OPT_PRIVACY) ) { 01441 ast_verb(3, "Privacy DB is '%s', clid is '%s'\n", opt_args[OPT_ARG_PRIVACY], l); 01442 pa->privdb_val = ast_privacy_check(opt_args[OPT_ARG_PRIVACY], l); 01443 } else { 01444 ast_verb(3, "Privacy Screening, clid is '%s'\n", l); 01445 pa->privdb_val = AST_PRIVACY_UNKNOWN; 01446 } 01447 } else { 01448 char *tnam, *tn2; 01449 01450 tnam = ast_strdupa(chan->name); 01451 /* clean the channel name so slashes don't try to end up in disk file name */ 01452 for (tn2 = tnam; *tn2; tn2++) { 01453 if (*tn2 == '/') /* any other chars to be afraid of? */ 01454 *tn2 = '='; 01455 } 01456 ast_verb(3, "Privacy-- callerid is empty\n"); 01457 01458 snprintf(callerid, sizeof(callerid), "NOCALLERID_%s%s", chan->exten, tnam); 01459 l = callerid; 01460 pa->privdb_val = AST_PRIVACY_UNKNOWN; 01461 } 01462 01463 ast_copy_string(pa->privcid, l, sizeof(pa->privcid)); 01464 01465 if (strncmp(pa->privcid, "NOCALLERID", 10) != 0 && ast_test_flag64(opts, OPT_SCREEN_NOCALLERID)) { 01466 /* if callerid is set and OPT_SCREEN_NOCALLERID is set also */ 01467 ast_verb(3, "CallerID set (%s); N option set; Screening should be off\n", pa->privcid); 01468 pa->privdb_val = AST_PRIVACY_ALLOW; 01469 } else if (ast_test_flag64(opts, OPT_SCREEN_NOCALLERID) && strncmp(pa->privcid, "NOCALLERID", 10) == 0) { 01470 ast_verb(3, "CallerID blank; N option set; Screening should happen; dbval is %d\n", pa->privdb_val); 01471 } 01472 01473 if (pa->privdb_val == AST_PRIVACY_DENY) { 01474 ast_verb(3, "Privacy DB reports PRIVACY_DENY for this callerid. Dial reports unavailable\n"); 01475 ast_copy_string(pa->status, "NOANSWER", sizeof(pa->status)); 01476 return 0; 01477 } else if (pa->privdb_val == AST_PRIVACY_KILL) { 01478 ast_copy_string(pa->status, "DONTCALL", sizeof(pa->status)); 01479 return 0; /* Is this right? */ 01480 } else if (pa->privdb_val == AST_PRIVACY_TORTURE) { 01481 ast_copy_string(pa->status, "TORTURE", sizeof(pa->status)); 01482 return 0; /* is this right??? */ 01483 } else if (pa->privdb_val == AST_PRIVACY_UNKNOWN) { 01484 /* Get the user's intro, store it in priv-callerintros/$CID, 01485 unless it is already there-- this should be done before the 01486 call is actually dialed */ 01487 01488 /* make sure the priv-callerintros dir actually exists */ 01489 snprintf(pa->privintro, sizeof(pa->privintro), "%s/sounds/priv-callerintros", ast_config_AST_DATA_DIR); 01490 if ((res = ast_mkdir(pa->privintro, 0755))) { 01491 ast_log(LOG_WARNING, "privacy: can't create directory priv-callerintros: %s\n", strerror(res)); 01492 return -1; 01493 } 01494 01495 snprintf(pa->privintro, sizeof(pa->privintro), "priv-callerintros/%s", pa->privcid); 01496 if (ast_fileexists(pa->privintro, NULL, NULL ) > 0 && strncmp(pa->privcid, "NOCALLERID", 10) != 0) { 01497 /* the DELUX version of this code would allow this caller the 01498 option to hear and retape their previously recorded intro. 01499 */ 01500 } else { 01501 int duration; /* for feedback from play_and_wait */ 01502 /* the file doesn't exist yet. Let the caller submit his 01503 vocal intro for posterity */ 01504 /* priv-recordintro script: 01505 01506 "At the tone, please say your name:" 01507 01508 */ 01509 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE); 01510 ast_answer(chan); 01511 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 */ 01512 /* don't think we'll need a lock removed, we took care of 01513 conflicts by naming the pa.privintro file */ 01514 if (res == -1) { 01515 /* Delete the file regardless since they hung up during recording */ 01516 ast_filedelete(pa->privintro, NULL); 01517 if (ast_fileexists(pa->privintro, NULL, NULL) > 0) 01518 ast_log(LOG_NOTICE, "privacy: ast_filedelete didn't do its job on %s\n", pa->privintro); 01519 else 01520 ast_verb(3, "Successfully deleted %s intro file\n", pa->privintro); 01521 return -1; 01522 } 01523 if (!ast_streamfile(chan, "vm-dialout", chan->language) ) 01524 ast_waitstream(chan, ""); 01525 } 01526 } 01527 return 1; /* success */ 01528 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 2468 of file app_dial.c.
References ast_context_destroy(), ast_context_find(), ast_context_remove_extension2(), and ast_unregister_application().
02469 { 02470 int res; 02471 struct ast_context *con; 02472 02473 res = ast_unregister_application(app); 02474 res |= ast_unregister_application(rapp); 02475 02476 if ((con = ast_context_find("app_dial_gosub_virtual_context"))) { 02477 ast_context_remove_extension2(con, "s", 1, NULL, 0); 02478 ast_context_destroy(con, "app_dial"); /* leave nothing behind */ 02479 } 02480 02481 return res; 02482 }
| static int valid_priv_reply | ( | struct ast_flags64 * | opts, | |
| int | res | |||
| ) | [static] |
Definition at line 1283 of file app_dial.c.
References ast_test_flag64, OPT_PRIVACY, and OPT_SCREENING.
01284 { 01285 if (res < '1') 01286 return 0; 01287 if (ast_test_flag64(opts, OPT_PRIVACY) && res <= '5') 01288 return 1; 01289 if (ast_test_flag64(opts, OPT_SCREENING) && res <= '4') 01290 return 1; 01291 return 0; 01292 }
| 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, | |||
| char * | dtmf_progress | |||
| ) | [static, read] |
Definition at line 871 of file app_dial.c.
References ast_channel::_state, ast_cdr::answer, AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, AST_CAUSE_NORMAL_CLEARING, AST_CDR_ANSWERED, ast_cdr_noanswer(), ast_channel_connected_line_macro(), ast_channel_early_bridge(), ast_channel_lock, ast_channel_make_compatible(), ast_channel_sendhtml(), ast_channel_unlock, ast_channel_update_connected_line(), ast_check_hangup(), ast_clear_flag64, ast_connected_line_copy_from_caller(), ast_connected_line_parse_data(), AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_CONNECTED_LINE, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OFFHOOK, AST_CONTROL_PROCEEDING, AST_CONTROL_PROGRESS, AST_CONTROL_REDIRECTING, AST_CONTROL_RINGING, AST_CONTROL_SRCUPDATE, AST_CONTROL_UNHOLD, AST_CONTROL_VIDUPDATE, ast_copy_flags64, ast_copy_string(), ast_deactivate_generator(), ast_debug, ast_dtmf_stream(), AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_HTML, AST_FRAME_IMAGE, AST_FRAME_TEXT, AST_FRAME_VOICE, ast_frfree, ast_hangup(), ast_indicate(), ast_indicate_data(), ast_log(), AST_MAX_WATCHERS, ast_party_connected_line_free(), ast_party_connected_line_init(), ast_party_connected_line_set(), ast_party_connected_line_set_init(), ast_poll_channel_add(), ast_poll_channel_del(), ast_read(), AST_STATE_UP, ast_str_alloca, ast_string_field_set, ast_strlen_zero(), ast_test_flag64, ast_tvnow(), ast_verb, ast_waitfor_n(), ast_write(), cause_args::busy, ast_channel::call_forward, CAN_EARLY_BRIDGE, ast_channel::cdr, chanlist::chan, ast_channel::cid, cause_args::congestion, chanlist::connected, context, ast_frame::data, ast_frame::datalen, detect_disconnect(), DIAL_NOCONNECTEDLINE, DIAL_NOFORWARDHTML, DIAL_STILLGOING, dialcontext, ast_cdr::disposition, do_forward(), ast_channel::exten, f, FEATURE_MAX_LEN, ast_frame::frametype, handle_cause(), ast_channel::hangupcause, ast_party_connected_line::id, LOG_WARNING, ast_channel::name, chanlist::next, cause_args::nochan, ast_party_id::number, onedigit_goto(), OPT_CALLEE_HANGUP, OPT_CALLEE_MIXMONITOR, OPT_CALLEE_MONITOR, OPT_CALLEE_PARK, OPT_CALLEE_TRANSFER, OPT_CALLER_HANGUP, OPT_CALLER_MIXMONITOR, OPT_CALLER_MONITOR, OPT_CALLER_PARK, OPT_CALLER_TRANSFER, OPT_DTMF_EXIT, OPT_IGNORE_CONNECTEDLINE, OPT_MUSICBACK, OPT_RINGBACK, pbx_builtin_getvar_helper(), ast_frame::ptr, privacy_args::sentringing, ast_party_connected_line::source, privacy_args::status, ast_frame::subclass, and ast_frame::uint32.
Referenced by dial_exec_full(), and try_calling().
00875 { 00876 struct cause_args num = *num_in; 00877 int prestart = num.busy + num.congestion + num.nochan; 00878 int orig = *to; 00879 struct ast_channel *peer = NULL; 00880 /* single is set if only one destination is enabled */ 00881 int single = outgoing && !outgoing->next; 00882 #ifdef HAVE_EPOLL 00883 struct chanlist *epollo; 00884 #endif 00885 struct ast_party_connected_line connected_caller; 00886 struct ast_str *featurecode = ast_str_alloca(FEATURE_MAX_LEN + 1); 00887 00888 ast_party_connected_line_init(&connected_caller); 00889 if (single) { 00890 /* Turn off hold music, etc */ 00891 if (!ast_test_flag64(outgoing, OPT_MUSICBACK | OPT_RINGBACK)) 00892 ast_deactivate_generator(in); 00893 00894 /* If we are calling a single channel, make them compatible for in-band tone purpose */ 00895 ast_channel_make_compatible(outgoing->chan, in); 00896 00897 if (!ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE) && !ast_test_flag64(outgoing, DIAL_NOCONNECTEDLINE)) { 00898 ast_channel_lock(outgoing->chan); 00899 ast_connected_line_copy_from_caller(&connected_caller, &outgoing->chan->cid); 00900 ast_channel_unlock(outgoing->chan); 00901 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 00902 ast_channel_update_connected_line(in, &connected_caller); 00903 ast_party_connected_line_free(&connected_caller); 00904 } 00905 } 00906 00907 #ifdef HAVE_EPOLL 00908 for (epollo = outgoing; epollo; epollo = epollo->next) 00909 ast_poll_channel_add(in, epollo->chan); 00910 #endif 00911 00912 while (*to && !peer) { 00913 struct chanlist *o; 00914 int pos = 0; /* how many channels do we handle */ 00915 int numlines = prestart; 00916 struct ast_channel *winner; 00917 struct ast_channel *watchers[AST_MAX_WATCHERS]; 00918 00919 watchers[pos++] = in; 00920 for (o = outgoing; o; o = o->next) { 00921 /* Keep track of important channels */ 00922 if (ast_test_flag64(o, DIAL_STILLGOING) && o->chan) 00923 watchers[pos++] = o->chan; 00924 numlines++; 00925 } 00926 if (pos == 1) { /* only the input channel is available */ 00927 if (numlines == (num.busy + num.congestion + num.nochan)) { 00928 ast_verb(2, "Everyone is busy/congested at this time (%d:%d/%d/%d)\n", numlines, num.busy, num.congestion, num.nochan); 00929 if (num.busy) 00930 strcpy(pa->status, "BUSY"); 00931 else if (num.congestion) 00932 strcpy(pa->status, "CONGESTION"); 00933 else if (num.nochan) 00934 strcpy(pa->status, "CHANUNAVAIL"); 00935 } else { 00936 ast_verb(3, "No one is available to answer at this time (%d:%d/%d/%d)\n", numlines, num.busy, num.congestion, num.nochan); 00937 } 00938 *to = 0; 00939 return NULL; 00940 } 00941 winner = ast_waitfor_n(watchers, pos, to); 00942 for (o = outgoing; o; o = o->next) { 00943 struct ast_frame *f; 00944 struct ast_channel *c = o->chan; 00945 00946 if (c == NULL) 00947 continue; 00948 if (ast_test_flag64(o, DIAL_STILLGOING) && c->_state == AST_STATE_UP) { 00949 if (!peer) { 00950 ast_verb(3, "%s answered %s\n", c->name, in->name); 00951 if (!single && !ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) { 00952 if (o->connected.id.number) { 00953 if (ast_channel_connected_line_macro(c, in, &o->connected, 1, 0)) { 00954 ast_channel_update_connected_line(in, &o->connected); 00955 } 00956 } else if (!ast_test_flag64(o, DIAL_NOCONNECTEDLINE)) { 00957 ast_channel_lock(c); 00958 ast_connected_line_copy_from_caller(&connected_caller, &c->cid); 00959 ast_channel_unlock(c); 00960 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 00961 ast_channel_update_connected_line(in, &connected_caller); 00962 ast_party_connected_line_free(&connected_caller); 00963 } 00964 } 00965 peer = c; 00966 ast_copy_flags64(peerflags, o, 00967 OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER | 00968 OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP | 00969 OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR | 00970 OPT_CALLEE_PARK | OPT_CALLER_PARK | 00971 OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR | 00972 DIAL_NOFORWARDHTML); 00973 ast_string_field_set(c, dialcontext, ""); 00974 ast_copy_string(c->exten, "", sizeof(c->exten)); 00975 } 00976 continue; 00977 } 00978 if (c != winner) 00979 continue; 00980 /* here, o->chan == c == winner */ 00981 if (!ast_strlen_zero(c->call_forward)) { 00982 pa->sentringing = 0; 00983 do_forward(o, &num, peerflags, single, to); 00984 continue; 00985 } 00986 f = ast_read(winner); 00987 if (!f) { 00988 in->hangupcause = c->hangupcause; 00989 #ifdef HAVE_EPOLL 00990 ast_poll_channel_del(in, c); 00991 #endif 00992 ast_hangup(c); 00993 c = o->chan = NULL; 00994 ast_clear_flag64(o, DIAL_STILLGOING); 00995 handle_cause(in->hangupcause, &num); 00996 continue; 00997 } 00998 if (f->frametype == AST_FRAME_CONTROL) { 00999 switch(f->subclass) { 01000 case AST_CONTROL_ANSWER: 01001 /* This is our guy if someone answered. */ 01002 if (!peer) { 01003 ast_verb(3, "%s answered %s\n", c->name, in->name); 01004 if (!single && !ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) { 01005 if (o->connected.id.number) { 01006 if (ast_channel_connected_line_macro(c, in, &o->connected, 1, 0)) { 01007 ast_channel_update_connected_line(in, &o->connected); 01008 } 01009 } else if (!ast_test_flag64(o, DIAL_NOCONNECTEDLINE)) { 01010 ast_channel_lock(c); 01011 ast_connected_line_copy_from_caller(&connected_caller, &c->cid); 01012 ast_channel_unlock(c); 01013 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER; 01014 ast_channel_update_connected_line(in, &connected_caller); 01015 ast_party_connected_line_free(&connected_caller); 01016 } 01017 } 01018 peer = c; 01019 if (peer->cdr) { 01020 peer->cdr->answer = ast_tvnow(); 01021 peer->cdr->disposition = AST_CDR_ANSWERED; 01022 } 01023 ast_copy_flags64(peerflags, o, 01024 OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER | 01025 OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP | 01026 OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR | 01027 OPT_CALLEE_PARK | OPT_CALLER_PARK | 01028 OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR | 01029 DIAL_NOFORWARDHTML); 01030 ast_string_field_set(c, dialcontext, ""); 01031 ast_copy_string(c->exten, "", sizeof(c->exten)); 01032 if (CAN_EARLY_BRIDGE(peerflags, in, peer)) 01033 /* Setup early bridge if appropriate */ 01034 ast_channel_early_bridge(in, peer); 01035 } 01036 /* If call has been answered, then the eventual hangup is likely to be normal hangup */ 01037 in->hangupcause = AST_CAUSE_NORMAL_CLEARING; 01038 c->hangupcause = AST_CAUSE_NORMAL_CLEARING; 01039 break; 01040 case AST_CONTROL_BUSY: 01041 ast_verb(3, "%s is busy\n", c->name); 01042 in->hangupcause = c->hangupcause; 01043 ast_hangup(c); 01044 c = o->chan = NULL; 01045 ast_clear_flag64(o, DIAL_STILLGOING); 01046 handle_cause(AST_CAUSE_BUSY, &num); 01047 break; 01048 case AST_CONTROL_CONGESTION: 01049 ast_verb(3, "%s is circuit-busy\n", c->name); 01050 in->hangupcause = c->hangupcause; 01051 ast_hangup(c); 01052 c = o->chan = NULL; 01053 ast_clear_flag64(o, DIAL_STILLGOING); 01054 handle_cause(AST_CAUSE_CONGESTION, &num); 01055 break; 01056 case AST_CONTROL_RINGING: 01057 ast_verb(3, "%s is ringing\n", c->name); 01058 /* Setup early media if appropriate */ 01059 if (single && CAN_EARLY_BRIDGE(peerflags, in, c)) 01060 ast_channel_early_bridge(in, c); 01061 if (!(pa->sentringing) && !ast_test_flag64(outgoing, OPT_MUSICBACK)) { 01062 ast_indicate(in, AST_CONTROL_RINGING); 01063 pa->sentringing++; 01064 } 01065 break; 01066 case AST_CONTROL_PROGRESS: 01067 ast_verb(3, "%s is making progress passing it to %s\n", c->name, in->name); 01068 /* Setup early media if appropriate */ 01069 if (single && CAN_EARLY_BRIDGE(peerflags, in, c)) 01070 ast_channel_early_bridge(in, c); 01071 if (!ast_test_flag64(outgoing, OPT_RINGBACK)) 01072 if (single || (!single && !pa->sentringing)) { 01073 ast_indicate(in, AST_CONTROL_PROGRESS); 01074 } 01075 if(!ast_strlen_zero(dtmf_progress)) { 01076 ast_verb(3, "Sending DTMF '%s' to the called party as result of receiving a PROGRESS message.\n", dtmf_progress); 01077 ast_dtmf_stream(c, in, dtmf_progress, 250, 0); 01078 } 01079 break; 01080 case AST_CONTROL_VIDUPDATE: 01081 ast_verb(3, "%s requested a video update, passing it to %s\n", c->name, in->name); 01082 ast_indicate(in, AST_CONTROL_VIDUPDATE); 01083 break; 01084 case AST_CONTROL_SRCUPDATE: 01085 ast_verb(3, "%s requested a source update, passing it to %s\n", c->name, in->name); 01086 ast_indicate(in, AST_CONTROL_SRCUPDATE); 01087 break; 01088 case AST_CONTROL_CONNECTED_LINE: 01089 if (ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) { 01090 ast_verb(3, "Connected line update to %s prevented.\n", in->name); 01091 } else if (!single) { 01092 struct ast_party_connected_line connected; 01093 ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", c->name, in->name); 01094 ast_party_connected_line_set_init(&connected, &o->connected); 01095 ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected); 01096 ast_party_connected_line_set(&o->connected, &connected); 01097 ast_party_connected_line_free(&connected); 01098 } else { 01099 if (ast_channel_connected_line_macro(c, in, f, 1, 1)) { 01100 ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen); 01101 } 01102 } 01103 break; 01104 case AST_CONTROL_REDIRECTING: 01105 if (ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) { 01106 ast_verb(3, "Redirecting update to %s prevented.\n", in->name); 01107 } else { 01108 ast_verb(3, "%s redirecting info has changed, passing it to %s\n", c->name, in->name); 01109 ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen); 01110 pa->sentringing = 0; 01111 } 01112 break; 01113 case AST_CONTROL_PROCEEDING: 01114 ast_verb(3, "%s is proceeding passing it to %s\n", c->name, in->name); 01115 if (single && CAN_EARLY_BRIDGE(peerflags, in, c)) 01116 ast_channel_early_bridge(in, c); 01117 if (!ast_test_flag64(outgoing, OPT_RINGBACK)) 01118 ast_indicate(in, AST_CONTROL_PROCEEDING); 01119 break; 01120 case AST_CONTROL_HOLD: 01121 ast_verb(3, "Call on %s placed on hold\n", c->name); 01122 ast_indicate(in, AST_CONTROL_HOLD); 01123 break; 01124 case AST_CONTROL_UNHOLD: 01125 ast_verb(3, "Call on %s left from hold\n", c->name); 01126 ast_indicate(in, AST_CONTROL_UNHOLD); 01127 break; 01128 case AST_CONTROL_OFFHOOK: 01129 case AST_CONTROL_FLASH: 01130 /* Ignore going off hook and flash */ 01131 break; 01132 case -1: 01133 if (!ast_test_flag64(outgoing, OPT_RINGBACK | OPT_MUSICBACK)) { 01134 ast_verb(3, "%s stopped sounds\n", c->name); 01135 ast_indicate(in, -1); 01136 pa->sentringing = 0; 01137 } 01138 break; 01139 default: 01140 ast_debug(1, "Dunno what to do with control type %d\n", f->subclass); 01141 } 01142 } else if (single) { 01143 switch (f->frametype) { 01144 case AST_FRAME_VOICE: 01145 case AST_FRAME_IMAGE: 01146 case AST_FRAME_TEXT: 01147 if (ast_write(in, f)) { 01148 ast_log(LOG_WARNING, "Unable to write frame\n"); 01149 } 01150 break; 01151 case AST_FRAME_HTML: 01152 if (!ast_test_flag64(outgoing, DIAL_NOFORWARDHTML) && ast_channel_sendhtml(in, f->subclass, f->data.ptr, f->datalen) == -1) { 01153 ast_log(LOG_WARNING, "Unable to send URL\n"); 01154 } 01155 break; 01156 default: 01157 break; 01158 } 01159 } 01160 ast_frfree(f); 01161 } /* end for */ 01162 if (winner == in) { 01163 struct ast_frame *f = ast_read(in); 01164 #if 0 01165 if (f && (f->frametype != AST_FRAME_VOICE)) 01166 printf("Frame type: %d, %d\n", f->frametype, f->subclass); 01167 else if (!f || (f->frametype != AST_FRAME_VOICE)) 01168 printf("Hangup received on %s\n", in->name); 01169 #endif 01170 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) { 01171 /* Got hung up */ 01172 *to = -1; 01173 strcpy(pa->status, "CANCEL"); 01174 ast_cdr_noanswer(in->cdr); 01175 if (f) { 01176 if (f->data.uint32) { 01177 in->hangupcause = f->data.uint32; 01178 } 01179 ast_frfree(f); 01180 } 01181 return NULL; 01182 } 01183 01184 /* now f is guaranteed non-NULL */ 01185 if (f->frametype == AST_FRAME_DTMF) { 01186 if (ast_test_flag64(peerflags, OPT_DTMF_EXIT)) { 01187 const char *context; 01188 ast_channel_lock(in); 01189 context = pbx_builtin_getvar_helper(in, "EXITCONTEXT"); 01190 if (onedigit_goto(in, context, (char) f->subclass, 1)) { 01191 ast_verb(3, "User hit %c to disconnect call.\n", f->subclass); 01192 *to = 0; 01193 ast_cdr_noanswer(in->cdr); 01194 *result = f->subclass; 01195 strcpy(pa->status, "CANCEL"); 01196 ast_frfree(f); 01197 ast_channel_unlock(in); 01198 return NULL; 01199 } 01200 ast_channel_unlock(in); 01201 } 01202 01203 if (ast_test_flag64(peerflags, OPT_CALLER_HANGUP) && 01204 detect_disconnect(in, f->subclass, featurecode)) { 01205 ast_verb(3, "User requested call disconnect.\n"); 01206 *to = 0; 01207 strcpy(pa->status, "CANCEL"); 01208 ast_cdr_noanswer(in->cdr); 01209 ast_frfree(f); 01210 return NULL; 01211 } 01212 } 01213 01214 /* Forward HTML stuff */ 01215 if (single && (f->frametype == AST_FRAME_HTML) && !ast_test_flag64(outgoing, DIAL_NOFORWARDHTML)) 01216 if (ast_channel_sendhtml(outgoing->chan, f->subclass, f->data.ptr, f->datalen) == -1) 01217 ast_log(LOG_WARNING, "Unable to send URL\n"); 01218 01219 if (single && ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_DTMF_BEGIN) || (f->frametype == AST_FRAME_DTMF_END))) { 01220 if (ast_write(outgoing->chan, f)) 01221 ast_log(LOG_WARNING, "Unable to forward voice or dtmf\n"); 01222 } 01223 if (single && (f->frametype == AST_FRAME_CONTROL)) { 01224 if ((f->subclass == AST_CONTROL_HOLD) || 01225 (f->subclass == AST_CONTROL_UNHOLD) || 01226 (f->subclass == AST_CONTROL_VIDUPDATE) || 01227 (f->subclass == AST_CONTROL_SRCUPDATE) || 01228 (f->subclass == AST_CONTROL_REDIRECTING)) { 01229 ast_verb(3, "%s requested special control %d, passing it to %s\n", in->name, f->subclass, outgoing->chan->name); 01230 ast_indicate_data(outgoing->chan, f->subclass, f->data.ptr, f->datalen); 01231 } else if (f->subclass == AST_CONTROL_CONNECTED_LINE) { 01232 if (ast_channel_connected_line_macro(in, outgoing->chan, f, 0, 1)) { 01233 ast_indicate_data(outgoing->chan, f->subclass, f->data.ptr, f->datalen); 01234 } 01235 } 01236 } 01237 ast_frfree(f); 01238 } 01239 if (!*to) 01240 ast_verb(3, "Nobody picked up in %d ms\n", orig); 01241 if (!*to || ast_check_hangup(in)) 01242 ast_cdr_noanswer(in->cdr); 01243 } 01244 01245 #ifdef HAVE_EPOLL 01246 for (epollo = outgoing; epollo; epollo = epollo->next) { 01247 if (epollo->chan) 01248 ast_poll_channel_del(in, epollo->chan); 01249 } 01250 #endif 01251 01252 return peer; 01253 }
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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, } [static] |
Definition at line 2501 of file app_dial.c.
const char app[] = "Dial" [static] |
Definition at line 469 of file app_dial.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 2501 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 << 34) }, [ 'd' ] = { .flag = OPT_DTMF_EXIT }, [ 'D' ] = { .flag = OPT_SENDDTMF , .arg_index = OPT_ARG_SENDDTMF + 1 }, [ 'e' ] = { .flag = ((uint64_t)1 << 35) }, [ 'f' ] = { .flag = OPT_FORCECLID }, [ 'F' ] = { .flag = ((uint64_t)1 << 36) , .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 }, [ 'I' ] = { .flag = OPT_IGNORE_CONNECTEDLINE }, [ '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_NOCALLERID }, [ '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 }, [ 'z' ] = { .flag = ((uint64_t)1 << 37) }, } [static] |
const char rapp[] = "RetryDial" [static] |
Definition at line 470 of file app_dial.c.
1.5.6