Wed Oct 28 13:31:20 2009

Asterisk developer's documentation


app_dial.c File Reference

dial() & retrydial() - Trivial application to dial a channel and send an URL on answer More...

#include "asterisk.h"
#include <sys/time.h>
#include <sys/signal.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include "asterisk/paths.h"
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/say.h"
#include "asterisk/config.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/callerid.h"
#include "asterisk/utils.h"
#include "asterisk/app.h"
#include "asterisk/causes.h"
#include "asterisk/rtp_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"

Include dependency graph for app_dial.c:

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_channelwait_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_infoast_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"


Detailed Description

dial() & retrydial() - Trivial application to dial a channel and send an URL on answer

Author:
Mark Spencer <markster@digium.com>

Definition in file app_dial.c.


Define Documentation

#define AST_MAX_WATCHERS   256

Definition at line 614 of file app_dial.c.

Referenced by monitor_dial(), and wait_for_answer().

#define CAN_EARLY_BRIDGE ( flags,
chan,
peer   ) 

#define DIAL_NOCONNECTEDLINE   ((uint64_t)1 << 33)

Definition at line 508 of file app_dial.c.

Referenced by dial_exec_full(), and wait_for_answer().

#define DIAL_NOFORWARDHTML   ((uint64_t)1 << 32)

Definition at line 507 of file app_dial.c.

Referenced by dial_exec_full(), and wait_for_answer().

#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)

Definition at line 511 of file app_dial.c.

Referenced by dial_exec_full().

#define OPT_CANCEL_ELSEWHERE   ((uint64_t)1 << 34)

Definition at line 509 of file app_dial.c.

Referenced by dial_exec_full().

#define OPT_CANCEL_TIMEOUT   ((uint64_t)1 << 37)

Definition at line 512 of file app_dial.c.

Referenced by dial_exec_full(), and do_forward().

#define OPT_PEER_H   ((uint64_t)1 << 35)

Definition at line 510 of file app_dial.c.

Referenced by dial_exec_full().

#define S_REPLACE ( s,
new_val   ) 

Value:

do {           \
      if (s)         \
         ast_free(s);   \
      s = (new_val);    \
   } while (0)

Definition at line 665 of file app_dial.c.

Referenced by begin_dial_channel(), dial_exec_full(), and do_forward().


Enumeration Type Documentation

anonymous enum

Enumerator:
OPT_ARG_ANNOUNCE 
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 

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

Enumerator:
OPT_ANNOUNCE 
OPT_RESETCDR 
OPT_DTMF_EXIT 
OPT_SENDDTMF 
OPT_FORCECLID 
OPT_GO_ON 
OPT_CALLEE_HANGUP 
OPT_CALLER_HANGUP 
OPT_ORIGINAL_CLID 
OPT_DURATION_LIMIT 
OPT_MUSICBACK 
OPT_CALLEE_MACRO 
OPT_SCREEN_NOINTRO 
OPT_SCREEN_NOCALLERID 
OPT_IGNORE_CONNECTEDLINE 
OPT_SCREENING 
OPT_PRIVACY 
OPT_RINGBACK 
OPT_DURATION_STOP 
OPT_CALLEE_TRANSFER 
OPT_CALLER_TRANSFER 
OPT_CALLEE_MONITOR 
OPT_CALLER_MONITOR 
OPT_GOTO 
OPT_OPERMODE 
OPT_CALLEE_PARK 
OPT_CALLER_PARK 
OPT_IGNORE_FORWARDING 
OPT_CALLEE_GOSUB 
OPT_CALLEE_MIXMONITOR 
OPT_CALLER_MIXMONITOR 

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 };


Function Documentation

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.

Todo:
eventually this function should be intergrated into and replaced by ast_call_forward()

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]

Definition at line 1275 of file app_dial.c.

Referenced by dial_exec_full().

01276 {
01277    for (; *s; s++)
01278       if (*s == '^')
01279          *s = ',';
01280 }

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 }


Variable Documentation

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.

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]

Definition at line 566 of file app_dial.c.

Referenced by dial_exec_full().

const char rapp[] = "RetryDial" [static]

Definition at line 470 of file app_dial.c.


Generated on Wed Oct 28 13:31:21 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6