Fri Nov 12 11:48:53 2010

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.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 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_NOFORWARDHTML   ((uint64_t)1 << 32)
#define DIAL_STILLGOING   (1 << 31)
#define OPT_CALLEE_GO_ON   ((uint64_t)1 << 35)
#define OPT_CANCEL_ELSEWHERE   ((uint64_t)1 << 33)
#define OPT_PEER_H   ((uint64_t)1 << 34)
#define S_REPLACE(s, new_val)

Enumerations

enum  {
  OPT_ARG_ANNOUNCE = 0, OPT_ARG_SENDDTMF, OPT_ARG_GOTO, OPT_ARG_DURATION_LIMIT,
  OPT_ARG_MUSICBACK, OPT_ARG_CALLEE_MACRO, OPT_ARG_CALLEE_GOSUB, OPT_ARG_CALLEE_GO_ON,
  OPT_ARG_PRIVACY, OPT_ARG_DURATION_STOP, OPT_ARG_OPERMODE, OPT_ARG_SCREEN_NOINTRO,
  OPT_ARG_ARRAY_SIZE
}
enum  {
  OPT_ANNOUNCE = (1 << 0), OPT_RESETCDR = (1 << 1), OPT_DTMF_EXIT = (1 << 2), OPT_SENDDTMF = (1 << 3),
  OPT_FORCECLID = (1 << 4), OPT_GO_ON = (1 << 5), OPT_CALLEE_HANGUP = (1 << 6), OPT_CALLER_HANGUP = (1 << 7),
  OPT_DURATION_LIMIT = (1 << 9), OPT_MUSICBACK = (1 << 10), OPT_CALLEE_MACRO = (1 << 11), OPT_SCREEN_NOINTRO = (1 << 12),
  OPT_SCREEN_NOCLID = (1 << 13), OPT_ORIGINAL_CLID = (1 << 14), OPT_SCREENING = (1 << 15), OPT_PRIVACY = (1 << 16),
  OPT_RINGBACK = (1 << 17), OPT_DURATION_STOP = (1 << 18), OPT_CALLEE_TRANSFER = (1 << 19), OPT_CALLER_TRANSFER = (1 << 20),
  OPT_CALLEE_MONITOR = (1 << 21), OPT_CALLER_MONITOR = (1 << 22), OPT_GOTO = (1 << 23), OPT_OPERMODE = (1 << 24),
  OPT_CALLEE_PARK = (1 << 25), OPT_CALLER_PARK = (1 << 26), OPT_IGNORE_FORWARDING = (1 << 27), OPT_CALLEE_GOSUB = (1 << 28),
  OPT_CALLEE_MIXMONITOR = (1 << 29), OPT_CALLER_MIXMONITOR = (1 << 30)
}

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int dial_exec (struct ast_channel *chan, void *data)
static int dial_exec_full (struct ast_channel *chan, void *data, struct ast_flags64 *peerflags, int *continue_exec)
static void do_forward (struct chanlist *o, struct cause_args *num, struct ast_flags64 *peerflags, int single)
static int do_timelimit (struct ast_channel *chan, struct ast_bridge_config *config, char *parse, struct timeval *calldurationlimit)
static void end_bridge_callback (void *data)
static void end_bridge_callback_data_fixup (struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
static const char * get_cid_name (char *name, int namelen, struct ast_channel *chan)
static void handle_cause (int cause, struct cause_args *num)
static void hanguptree (struct chanlist *outgoing, struct ast_channel *exception, int answered_elsewhere)
static int load_module (void)
static int onedigit_goto (struct ast_channel *chan, const char *context, char exten, int pri)
static void replace_macro_delimiter (char *s)
static int retrydial_exec (struct ast_channel *chan, void *data)
static void senddialendevent (const struct ast_channel *src, const char *dialstatus)
static void senddialevent (struct ast_channel *src, struct ast_channel *dst, const char *dialstring)
static int setup_privacy_args (struct privacy_args *pa, struct ast_flags64 *opts, char *opt_args[], struct ast_channel *chan)
 returns 1 if successful, 0 or <0 if the caller should 'goto out'
static int unload_module (void)
static int valid_priv_reply (struct ast_flags64 *opts, int res)
static struct ast_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)

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 = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, }
static 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 << 33) }, [ 'd' ] = { .flag = OPT_DTMF_EXIT }, [ 'D' ] = { .flag = OPT_SENDDTMF , .arg_index = OPT_ARG_SENDDTMF + 1 }, [ 'e' ] = { .flag = ((uint64_t)1 << 34) }, [ 'f' ] = { .flag = OPT_FORCECLID }, [ 'F' ] = { .flag = ((uint64_t)1 << 35) , .arg_index = OPT_ARG_CALLEE_GO_ON + 1 }, [ 'g' ] = { .flag = OPT_GO_ON }, [ 'G' ] = { .flag = OPT_GOTO , .arg_index = OPT_ARG_GOTO + 1 }, [ 'h' ] = { .flag = OPT_CALLEE_HANGUP }, [ 'H' ] = { .flag = OPT_CALLER_HANGUP }, [ 'i' ] = { .flag = OPT_IGNORE_FORWARDING }, [ 'k' ] = { .flag = OPT_CALLEE_PARK }, [ 'K' ] = { .flag = OPT_CALLER_PARK }, [ 'L' ] = { .flag = OPT_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, [ 'm' ] = { .flag = OPT_MUSICBACK , .arg_index = OPT_ARG_MUSICBACK + 1 }, [ 'M' ] = { .flag = OPT_CALLEE_MACRO , .arg_index = OPT_ARG_CALLEE_MACRO + 1 }, [ 'n' ] = { .flag = OPT_SCREEN_NOINTRO , .arg_index = OPT_ARG_SCREEN_NOINTRO + 1 }, [ 'N' ] = { .flag = OPT_SCREEN_NOCLID }, [ 'o' ] = { .flag = OPT_ORIGINAL_CLID }, [ 'O' ] = { .flag = OPT_OPERMODE , .arg_index = OPT_ARG_OPERMODE + 1 }, [ 'p' ] = { .flag = OPT_SCREENING }, [ 'P' ] = { .flag = OPT_PRIVACY , .arg_index = OPT_ARG_PRIVACY + 1 }, [ 'r' ] = { .flag = OPT_RINGBACK }, [ 'S' ] = { .flag = OPT_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 't' ] = { .flag = OPT_CALLEE_TRANSFER }, [ 'T' ] = { .flag = OPT_CALLER_TRANSFER }, [ 'U' ] = { .flag = OPT_CALLEE_GOSUB , .arg_index = OPT_ARG_CALLEE_GOSUB + 1 }, [ 'w' ] = { .flag = OPT_CALLEE_MONITOR }, [ 'W' ] = { .flag = OPT_CALLER_MONITOR }, [ 'x' ] = { .flag = OPT_CALLEE_MIXMONITOR }, [ 'X' ] = { .flag = OPT_CALLER_MIXMONITOR }, }
static char * rapp = "RetryDial"

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 595 of file app_dial.c.

Referenced by monitor_dial(), and wait_for_answer().

#define CAN_EARLY_BRIDGE ( flags,
chan,
peer   ) 
#define DIAL_NOFORWARDHTML   ((uint64_t)1 << 32)

Definition at line 500 of file app_dial.c.

Referenced by dial_exec_full(), and wait_for_answer().

#define DIAL_STILLGOING   (1 << 31)

Definition at line 499 of file app_dial.c.

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

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

Definition at line 503 of file app_dial.c.

Referenced by dial_exec_full().

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

Definition at line 501 of file app_dial.c.

Referenced by dial_exec_full().

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

Definition at line 502 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 646 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_SCREEN_NOINTRO 
OPT_ARG_ARRAY_SIZE 

Definition at line 505 of file app_dial.c.

00505      {
00506    OPT_ARG_ANNOUNCE = 0,
00507    OPT_ARG_SENDDTMF,
00508    OPT_ARG_GOTO,
00509    OPT_ARG_DURATION_LIMIT,
00510    OPT_ARG_MUSICBACK,
00511    OPT_ARG_CALLEE_MACRO,
00512    OPT_ARG_CALLEE_GOSUB,
00513    OPT_ARG_CALLEE_GO_ON,
00514    OPT_ARG_PRIVACY,
00515    OPT_ARG_DURATION_STOP,
00516    OPT_ARG_OPERMODE,
00517    OPT_ARG_SCREEN_NOINTRO,
00518    /* note: this entry _MUST_ be the last one in the enum */
00519    OPT_ARG_ARRAY_SIZE,
00520 };

anonymous enum
Enumerator:
OPT_ANNOUNCE 
OPT_RESETCDR 
OPT_DTMF_EXIT 
OPT_SENDDTMF 
OPT_FORCECLID 
OPT_GO_ON 
OPT_CALLEE_HANGUP 
OPT_CALLER_HANGUP 
OPT_DURATION_LIMIT 
OPT_MUSICBACK 
OPT_CALLEE_MACRO 
OPT_SCREEN_NOINTRO 
OPT_SCREEN_NOCLID 
OPT_ORIGINAL_CLID 
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 466 of file app_dial.c.

00466      {
00467    OPT_ANNOUNCE =          (1 << 0),
00468    OPT_RESETCDR =          (1 << 1),
00469    OPT_DTMF_EXIT =         (1 << 2),
00470    OPT_SENDDTMF =          (1 << 3),
00471    OPT_FORCECLID =         (1 << 4),
00472    OPT_GO_ON =             (1 << 5),
00473    OPT_CALLEE_HANGUP =     (1 << 6),
00474    OPT_CALLER_HANGUP =     (1 << 7),
00475    OPT_DURATION_LIMIT =    (1 << 9),
00476    OPT_MUSICBACK =         (1 << 10),
00477    OPT_CALLEE_MACRO =      (1 << 11),
00478    OPT_SCREEN_NOINTRO =    (1 << 12),
00479    OPT_SCREEN_NOCLID =     (1 << 13),
00480    OPT_ORIGINAL_CLID =     (1 << 14),
00481    OPT_SCREENING =         (1 << 15),
00482    OPT_PRIVACY =           (1 << 16),
00483    OPT_RINGBACK =          (1 << 17),
00484    OPT_DURATION_STOP =     (1 << 18),
00485    OPT_CALLEE_TRANSFER =   (1 << 19),
00486    OPT_CALLER_TRANSFER =   (1 << 20),
00487    OPT_CALLEE_MONITOR =    (1 << 21),
00488    OPT_CALLER_MONITOR =    (1 << 22),
00489    OPT_GOTO =              (1 << 23),
00490    OPT_OPERMODE =          (1 << 24),
00491    OPT_CALLEE_PARK =       (1 << 25),
00492    OPT_CALLER_PARK =       (1 << 26),
00493    OPT_IGNORE_FORWARDING = (1 << 27),
00494    OPT_CALLEE_GOSUB =      (1 << 28),
00495    OPT_CALLEE_MIXMONITOR = (1 << 29),
00496    OPT_CALLER_MIXMONITOR = (1 << 30),
00497 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 2486 of file app_dial.c.

static void __unreg_module ( void   )  [static]

Definition at line 2486 of file app_dial.c.

static int dial_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 2336 of file app_dial.c.

References dial_exec_full().

Referenced by load_module().

02337 {
02338    struct ast_flags64 peerflags;
02339 
02340    memset(&peerflags, 0, sizeof(peerflags));
02341 
02342    return dial_exec_full(chan, data, &peerflags, NULL);
02343 }

static int dial_exec_full ( struct ast_channel chan,
void *  data,
struct ast_flags64 peerflags,
int *  continue_exec 
) [static]

Definition at line 1515 of file app_dial.c.

References __ast_answer(), ast_channel::_state, ast_channel::accountcode, accountcode, ast_channel::adsicpe, ast_channel::appl, asprintf, AST_APP_ARG, ast_app_group_set_channel(), ast_app_parse_options64(), ast_autoservice_start(), ast_autoservice_stop(), ast_bridge_call(), ast_call(), ast_calloc, ast_cause2str(), AST_CAUSE_INVALID_NUMBER_FORMAT, ast_cdr_reset(), ast_cdr_setdestchan(), ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_datastore_inherit(), ast_channel_datastore_remove(), ast_channel_early_bridge(), ast_channel_inherit_variables(), ast_channel_lock, ast_channel_make_compatible(), ast_channel_sendurl(), ast_channel_setoption(), ast_channel_supports_html(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, AST_CONTROL_HANGUP, AST_CONTROL_PROGRESS, AST_CONTROL_RINGING, ast_copy_flags64, ast_copy_string(), ast_datastore_alloc, ast_datastore_free(), ast_deactivate_generator(), ast_debug, AST_DECLARE_APP_ARGS, AST_DIGIT_ANY, ast_dtmf_stream(), ast_exists_extension(), AST_FEATURE_AUTOMIXMON, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_NO_H_EXTEN, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, ast_filedelete(), ast_fileexists(), AST_FLAG_ANSWERED_ELSEWHERE, AST_FLAG_END_DTMF_ONLY, AST_FLAG_IN_AUTOLOOP, AST_FRAME_CONTROL, AST_FRAME_DTMF_END, ast_free, ast_frfree, ast_hangup(), ast_indicate(), AST_LIST_HEAD, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_EXTENSION, ast_moh_start(), ast_moh_stop(), AST_OPTION_OPRMODE, ast_parseable_goto(), AST_PBX_INCOMPLETE, ast_pbx_run_args(), ast_pbx_start(), AST_PRIVACY_UNKNOWN, ast_read(), ast_request(), ast_rtp_make_compatible(), ast_sched_runq(), ast_sched_wait(), ast_senddigit(), ast_set2_flag, ast_set2_flag64, ast_set_callerid(), ast_set_flag, ast_set_flag64, ast_spawn_extension(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_stopstream(), ast_strdup, ast_streamfile(), ast_string_field_set, ast_strlen_zero(), ast_test_flag, ast_test_flag64, ast_tvadd(), ast_tvnow(), ast_tvzero(), ast_verb, ast_waitfor_n(), CAN_EARLY_BRIDGE, cause, ast_channel::cdr, ast_channel::cdrflags, chanlist::chan, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_ani2, ast_callerid::cid_name, ast_callerid::cid_num, ast_callerid::cid_pres, ast_callerid::cid_rdnis, ast_callerid::cid_tns, ast_callerid::cid_ton, ast_channel::context, ast_channel::data, ast_datastore::data, DATASTORE_INHERIT_FOREVER, di, dial_exec_options, DIAL_NOFORWARDHTML, DIAL_STILLGOING, dialcontext, dialed_interface_info, do_timelimit(), end_bridge_callback(), 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, ast_frame::frametype, get_cid_name(), handle_cause(), ast_channel::hangupcause, hanguptree(), ast_datastore::inheritance, ast_dialed_interface::interface, ast_channel::language, ast_dialed_interface::list, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_channel::macrocontext, ast_channel::macroexten, oprmode::mode, moh, musicclass, ast_channel::musicclass, ast_channel::name, ast_channel::nativeformats, chanlist::next, ast_pbx_args::no_hangup_chan, OPT_ANNOUNCE, OPT_ARG_ANNOUNCE, OPT_ARG_ARRAY_SIZE, OPT_ARG_CALLEE_GO_ON, OPT_ARG_CALLEE_GOSUB, OPT_ARG_CALLEE_MACRO, OPT_ARG_DURATION_LIMIT, OPT_ARG_DURATION_STOP, OPT_ARG_GOTO, OPT_ARG_OPERMODE, OPT_ARG_PRIVACY, OPT_ARG_SCREEN_NOINTRO, OPT_ARG_SENDDTMF, OPT_CALLEE_GO_ON, OPT_CALLEE_GOSUB, OPT_CALLEE_HANGUP, OPT_CALLEE_MACRO, OPT_CALLEE_MIXMONITOR, OPT_CALLEE_MONITOR, OPT_CALLEE_PARK, OPT_CALLEE_TRANSFER, OPT_CALLER_HANGUP, OPT_CALLER_MIXMONITOR, OPT_CALLER_MONITOR, OPT_CALLER_PARK, OPT_CALLER_TRANSFER, OPT_CANCEL_ELSEWHERE, OPT_DTMF_EXIT, OPT_DURATION_LIMIT, OPT_DURATION_STOP, OPT_FORCECLID, OPT_GO_ON, OPT_GOTO, OPT_IGNORE_FORWARDING, OPT_MUSICBACK, OPT_OPERMODE, OPT_ORIGINAL_CLID, OPT_PEER_H, OPT_PRIVACY, OPT_RESETCDR, OPT_RINGBACK, OPT_SCREEN_NOINTRO, OPT_SCREENING, OPT_SENDDTMF, parse(), pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), oprmode::peer, ast_channel::priority, privacy_args::privdb_val, privacy_args::privintro, replace_macro_delimiter(), S_OR, S_REPLACE, ast_channel::sched, senddialendevent(), senddialevent(), privacy_args::sentringing, setup_privacy_args(), ast_bridge_config::start_sound, privacy_args::status, ast_channel::stream, ast_frame::subclass, ast_channel::tech, ast_channel::timingfunc, ast_channel::transfercapability, url, wait_for_answer(), ast_bridge_config::warning_sound, and ast_channel::whentohangup.

Referenced by dial_exec(), and retrydial_exec().

01516 {
01517    int res = -1; /* default: error */
01518    char *rest, *cur; /* scan the list of destinations */
01519    struct chanlist *outgoing = NULL; /* list of destinations */
01520    struct ast_channel *peer;
01521    int to; /* timeout */
01522    struct cause_args num = { chan, 0, 0, 0 };
01523    int cause;
01524    char numsubst[256];
01525    char cidname[AST_MAX_EXTENSION] = "";
01526 
01527    struct ast_bridge_config config = { { 0, } };
01528    struct timeval calldurationlimit = { 0, };
01529    char *dtmfcalled = NULL, *dtmfcalling = NULL;
01530    struct privacy_args pa = {
01531       .sentringing = 0,
01532       .privdb_val = 0,
01533       .status = "INVALIDARGS",
01534    };
01535    int sentringing = 0, moh = 0;
01536    const char *outbound_group = NULL;
01537    int result = 0;
01538    char *parse;
01539    int opermode = 0;
01540    int delprivintro = 0;
01541    AST_DECLARE_APP_ARGS(args,
01542       AST_APP_ARG(peers);
01543       AST_APP_ARG(timeout);
01544       AST_APP_ARG(options);
01545       AST_APP_ARG(url);
01546    );
01547    struct ast_flags64 opts = { 0, };
01548    char *opt_args[OPT_ARG_ARRAY_SIZE];
01549    struct ast_datastore *datastore = NULL;
01550    int fulldial = 0, num_dialed = 0;
01551 
01552    /* Reset all DIAL variables back to blank, to prevent confusion (in case we don't reset all of them). */
01553    pbx_builtin_setvar_helper(chan, "DIALSTATUS", "");
01554    pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", "");
01555    pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", "");
01556    pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", "");
01557    pbx_builtin_setvar_helper(chan, "DIALEDTIME", "");
01558 
01559    if (ast_strlen_zero(data)) {
01560       ast_log(LOG_WARNING, "Dial requires an argument (technology/number)\n");
01561       pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
01562       return -1;
01563    }
01564 
01565    parse = ast_strdupa(data);
01566 
01567    AST_STANDARD_APP_ARGS(args, parse);
01568 
01569    if (!ast_strlen_zero(args.options) &&
01570       ast_app_parse_options64(dial_exec_options, &opts, opt_args, args.options)) {
01571       pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
01572       goto done;
01573    }
01574 
01575    if (ast_strlen_zero(args.peers)) {
01576       ast_log(LOG_WARNING, "Dial requires an argument (technology/number)\n");
01577       pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
01578       goto done;
01579    }
01580 
01581 
01582    if (ast_test_flag64(&opts, OPT_SCREEN_NOINTRO) && !ast_strlen_zero(opt_args[OPT_ARG_SCREEN_NOINTRO])) {
01583       delprivintro = atoi(opt_args[OPT_ARG_SCREEN_NOINTRO]);
01584 
01585       if (delprivintro < 0 || delprivintro > 1) {
01586          ast_log(LOG_WARNING, "Unknown argument %d specified to n option, ignoring\n", delprivintro);
01587          delprivintro = 0;
01588       }
01589    }
01590 
01591    if (ast_test_flag64(&opts, OPT_OPERMODE)) {
01592       opermode = ast_strlen_zero(opt_args[OPT_ARG_OPERMODE]) ? 1 : atoi(opt_args[OPT_ARG_OPERMODE]);
01593       ast_verb(3, "Setting operator services mode to %d.\n", opermode);
01594    }
01595    
01596    if (ast_test_flag64(&opts, OPT_DURATION_STOP) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_STOP])) {
01597       calldurationlimit.tv_sec = atoi(opt_args[OPT_ARG_DURATION_STOP]);
01598       if (!calldurationlimit.tv_sec) {
01599          ast_log(LOG_WARNING, "Dial does not accept S(%s), hanging up.\n", opt_args[OPT_ARG_DURATION_STOP]);
01600          pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
01601          goto done;
01602       }
01603       ast_verb(3, "Setting call duration limit to %.3lf seconds.\n", calldurationlimit.tv_sec + calldurationlimit.tv_usec / 1000000.0);
01604    }
01605 
01606    if (ast_test_flag64(&opts, OPT_SENDDTMF) && !ast_strlen_zero(opt_args[OPT_ARG_SENDDTMF])) {
01607       dtmfcalling = opt_args[OPT_ARG_SENDDTMF];
01608       dtmfcalled = strsep(&dtmfcalling, ":");
01609    }
01610 
01611    if (ast_test_flag64(&opts, OPT_DURATION_LIMIT) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])) {
01612       if (do_timelimit(chan, &config, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit))
01613          goto done;
01614    }
01615 
01616    if (ast_test_flag64(&opts, OPT_RESETCDR) && chan->cdr)
01617       ast_cdr_reset(chan->cdr, NULL);
01618    if (ast_test_flag64(&opts, OPT_PRIVACY) && ast_strlen_zero(opt_args[OPT_ARG_PRIVACY]))
01619       opt_args[OPT_ARG_PRIVACY] = ast_strdupa(chan->exten);
01620 
01621    if (ast_test_flag64(&opts, OPT_PRIVACY) || ast_test_flag64(&opts, OPT_SCREENING)) {
01622       res = setup_privacy_args(&pa, &opts, opt_args, chan);
01623       if (res <= 0)
01624          goto out;
01625       res = -1; /* reset default */
01626    }
01627 
01628    if (ast_test_flag64(&opts, OPT_DTMF_EXIT)) {
01629       __ast_answer(chan, 0, 0);
01630    }
01631 
01632    if (continue_exec)
01633       *continue_exec = 0;
01634 
01635    /* If a channel group has been specified, get it for use when we create peer channels */
01636 
01637    ast_channel_lock(chan);
01638    if ((outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP_ONCE"))) {
01639       outbound_group = ast_strdupa(outbound_group);   
01640       pbx_builtin_setvar_helper(chan, "OUTBOUND_GROUP_ONCE", NULL);
01641    } else if ((outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP"))) {
01642       outbound_group = ast_strdupa(outbound_group);
01643    }
01644    ast_channel_unlock(chan);  
01645    ast_copy_flags64(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING | OPT_ANNOUNCE | OPT_CALLEE_MACRO | OPT_CALLEE_GOSUB);
01646 
01647    /* loop through the list of dial destinations */
01648    rest = args.peers;
01649    while ((cur = strsep(&rest, "&")) ) {
01650       struct chanlist *tmp;
01651       struct ast_channel *tc; /* channel for this destination */
01652       /* Get a technology/[device:]number pair */
01653       char *number = cur;
01654       char *interface = ast_strdupa(number);
01655       char *tech = strsep(&number, "/");
01656       /* find if we already dialed this interface */
01657       struct ast_dialed_interface *di;
01658       AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces;
01659       num_dialed++;
01660       if (!number) {
01661          ast_log(LOG_WARNING, "Dial argument takes format (technology/[device:]number1)\n");
01662          goto out;
01663       }
01664       if (!(tmp = ast_calloc(1, sizeof(*tmp))))
01665          goto out;
01666       if (opts.flags) {
01667          ast_copy_flags64(tmp, &opts,
01668             OPT_CANCEL_ELSEWHERE |
01669             OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
01670             OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
01671             OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
01672             OPT_CALLEE_PARK | OPT_CALLER_PARK |
01673             OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR |
01674             OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID);
01675          ast_set2_flag64(tmp, args.url, DIAL_NOFORWARDHTML);
01676       }
01677       ast_copy_string(numsubst, number, sizeof(numsubst));
01678       /* Request the peer */
01679 
01680       ast_channel_lock(chan);
01681       datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL);
01682       ast_channel_unlock(chan);
01683 
01684       if (datastore)
01685          dialed_interfaces = datastore->data;
01686       else {
01687          if (!(datastore = ast_datastore_alloc(&dialed_interface_info, NULL))) {
01688             ast_log(LOG_WARNING, "Unable to create channel datastore for dialed interfaces. Aborting!\n");
01689             ast_free(tmp);
01690             goto out;
01691          }
01692 
01693          datastore->inheritance = DATASTORE_INHERIT_FOREVER;
01694 
01695          if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) {
01696             ast_datastore_free(datastore);
01697             ast_free(tmp);
01698             goto out;
01699          }
01700 
01701          datastore->data = dialed_interfaces;
01702          AST_LIST_HEAD_INIT(dialed_interfaces);
01703 
01704          ast_channel_lock(chan);
01705          ast_channel_datastore_add(chan, datastore);
01706          ast_channel_unlock(chan);
01707       }
01708 
01709       AST_LIST_LOCK(dialed_interfaces);
01710       AST_LIST_TRAVERSE(dialed_interfaces, di, list) {
01711          if (!strcasecmp(di->interface, interface)) {
01712             ast_log(LOG_WARNING, "Skipping dialing interface '%s' again since it has already been dialed\n",
01713                di->interface);
01714             break;
01715          }
01716       }
01717       AST_LIST_UNLOCK(dialed_interfaces);
01718 
01719       if (di) {
01720          fulldial++;
01721          ast_free(tmp);
01722          continue;
01723       }
01724 
01725       /* It is always ok to dial a Local interface.  We only keep track of
01726        * which "real" interfaces have been dialed.  The Local channel will
01727        * inherit this list so that if it ends up dialing a real interface,
01728        * it won't call one that has already been called. */
01729       if (strcasecmp(tech, "Local")) {
01730          if (!(di = ast_calloc(1, sizeof(*di) + strlen(interface)))) {
01731             AST_LIST_UNLOCK(dialed_interfaces);
01732             ast_free(tmp);
01733             goto out;
01734          }
01735          strcpy(di->interface, interface);
01736 
01737          AST_LIST_LOCK(dialed_interfaces);
01738          AST_LIST_INSERT_TAIL(dialed_interfaces, di, list);
01739          AST_LIST_UNLOCK(dialed_interfaces);
01740       }
01741 
01742       tc = ast_request(tech, chan->nativeformats, numsubst, &cause);
01743       if (!tc) {
01744          /* If we can't, just go on to the next call */
01745          ast_log(LOG_WARNING, "Unable to create channel of type '%s' (cause %d - %s)\n",
01746             tech, cause, ast_cause2str(cause));
01747          handle_cause(cause, &num);
01748          if (!rest) /* we are on the last destination */
01749             chan->hangupcause = cause;
01750          ast_free(tmp);
01751          continue;
01752       }
01753       pbx_builtin_setvar_helper(tc, "DIALEDPEERNUMBER", numsubst);
01754 
01755       /* Setup outgoing SDP to match incoming one */
01756       if (CAN_EARLY_BRIDGE(peerflags, chan, tc)) {
01757          ast_rtp_make_compatible(tc, chan, !outgoing && !rest);
01758       }
01759       
01760       /* Inherit specially named variables from parent channel */
01761       ast_channel_inherit_variables(chan, tc);
01762       ast_channel_datastore_inherit(chan, tc);
01763 
01764       tc->appl = "AppDial";
01765       tc->data = "(Outgoing Line)";
01766       memset(&tc->whentohangup, 0, sizeof(tc->whentohangup));
01767 
01768       S_REPLACE(tc->cid.cid_num, ast_strdup(chan->cid.cid_num));
01769       S_REPLACE(tc->cid.cid_name, ast_strdup(chan->cid.cid_name));
01770       S_REPLACE(tc->cid.cid_ani, ast_strdup(chan->cid.cid_ani));
01771       S_REPLACE(tc->cid.cid_rdnis, ast_strdup(chan->cid.cid_rdnis));
01772       
01773       ast_string_field_set(tc, accountcode, chan->accountcode);
01774       tc->cdrflags = chan->cdrflags;
01775       if (ast_strlen_zero(tc->musicclass))
01776          ast_string_field_set(tc, musicclass, chan->musicclass);
01777       /* Pass callingpres, type of number, tns, ADSI CPE, transfer capability */
01778       tc->cid.cid_pres = chan->cid.cid_pres;
01779       tc->cid.cid_ton = chan->cid.cid_ton;
01780       tc->cid.cid_tns = chan->cid.cid_tns;
01781       tc->cid.cid_ani2 = chan->cid.cid_ani2;
01782       tc->adsicpe = chan->adsicpe;
01783       tc->transfercapability = chan->transfercapability;
01784 
01785       /* If we have an outbound group, set this peer channel to it */
01786       if (outbound_group)
01787          ast_app_group_set_channel(tc, outbound_group);
01788       /* If the calling channel has the ANSWERED_ELSEWHERE flag set, inherit it. This is to support local channels */
01789       if (ast_test_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE))
01790          ast_set_flag(tc, AST_FLAG_ANSWERED_ELSEWHERE);
01791 
01792       /* Check if we're forced by configuration */
01793       if (ast_test_flag64(&opts, OPT_CANCEL_ELSEWHERE))
01794           ast_set_flag(tc, AST_FLAG_ANSWERED_ELSEWHERE);
01795 
01796 
01797       /* Inherit context and extension */
01798       ast_string_field_set(tc, dialcontext, ast_strlen_zero(chan->macrocontext) ? chan->context : chan->macrocontext);
01799       if (!ast_strlen_zero(chan->macroexten))
01800          ast_copy_string(tc->exten, chan->macroexten, sizeof(tc->exten));
01801       else
01802          ast_copy_string(tc->exten, chan->exten, sizeof(tc->exten));
01803 
01804       res = ast_call(tc, numsubst, 0); /* Place the call, but don't wait on the answer */
01805 
01806       /* Save the info in cdr's that we called them */
01807       if (chan->cdr)
01808          ast_cdr_setdestchan(chan->cdr, tc->name);
01809 
01810       /* check the results of ast_call */
01811       if (res) {
01812          /* Again, keep going even if there's an error */
01813          ast_debug(1, "ast call on peer returned %d\n", res);
01814          ast_verb(3, "Couldn't call %s\n", numsubst);
01815          if (tc->hangupcause) {
01816             chan->hangupcause = tc->hangupcause;
01817          }
01818          ast_hangup(tc);
01819          tc = NULL;
01820          ast_free(tmp);
01821          continue;
01822       } else {
01823          senddialevent(chan, tc, numsubst);
01824          ast_verb(3, "Called %s\n", numsubst);
01825          if (!ast_test_flag64(peerflags, OPT_ORIGINAL_CLID))
01826             ast_set_callerid(tc, S_OR(chan->macroexten, chan->exten), get_cid_name(cidname, sizeof(cidname), chan), NULL);
01827       }
01828       /* Put them in the list of outgoing thingies...  We're ready now.
01829          XXX If we're forcibly removed, these outgoing calls won't get
01830          hung up XXX */
01831       ast_set_flag64(tmp, DIAL_STILLGOING);
01832       tmp->chan = tc;
01833       tmp->next = outgoing;
01834       outgoing = tmp;
01835       /* If this line is up, don't try anybody else */
01836       if (outgoing->chan->_state == AST_STATE_UP)
01837          break;
01838    }
01839    
01840    if (ast_strlen_zero(args.timeout)) {
01841       to = -1;
01842    } else {
01843       to = atoi(args.timeout);
01844       if (to > 0)
01845          to *= 1000;
01846       else {
01847          ast_log(LOG_WARNING, "Invalid timeout specified: '%s'. Setting timeout to infinite\n", args.timeout);
01848          to = -1;
01849       }
01850    }
01851 
01852    if (!outgoing) {
01853       strcpy(pa.status, "CHANUNAVAIL");
01854       if (fulldial == num_dialed) {
01855          res = -1;
01856          goto out;
01857       }
01858    } else {
01859       /* Our status will at least be NOANSWER */
01860       strcpy(pa.status, "NOANSWER");
01861       if (ast_test_flag64(outgoing, OPT_MUSICBACK)) {
01862          moh = 1;
01863          if (!ast_strlen_zero(opt_args[OPT_ARG_MUSICBACK])) {
01864             char *original_moh = ast_strdupa(chan->musicclass);
01865             ast_string_field_set(chan, musicclass, opt_args[OPT_ARG_MUSICBACK]);
01866             ast_moh_start(chan, opt_args[OPT_ARG_MUSICBACK], NULL);
01867             ast_string_field_set(chan, musicclass, original_moh);
01868          } else {
01869             ast_moh_start(chan, NULL, NULL);
01870          }
01871          ast_indicate(chan, AST_CONTROL_PROGRESS);
01872       } else if (ast_test_flag64(outgoing, OPT_RINGBACK)) {
01873          ast_indicate(chan, AST_CONTROL_RINGING);
01874          sentringing++;
01875       }
01876    }
01877 
01878    peer = wait_for_answer(chan, outgoing, &to, peerflags, &pa, &num, &result);
01879 
01880    /* The ast_channel_datastore_remove() function could fail here if the
01881     * datastore was moved to another channel during a masquerade. If this is
01882     * the case, don't free the datastore here because later, when the channel
01883     * to which the datastore was moved hangs up, it will attempt to free this
01884     * datastore again, causing a crash
01885     */
01886    if (!ast_channel_datastore_remove(chan, datastore))
01887       ast_datastore_free(datastore);
01888    if (!peer) {
01889       if (result) {
01890          res = result;
01891       } else if (to) { /* Musta gotten hung up */
01892          res = -1;
01893       } else { /* Nobody answered, next please? */
01894          res = 0;
01895       }
01896 
01897       /* SIP, in particular, sends back this error code to indicate an
01898        * overlap dialled number needs more digits. */
01899       if (chan->hangupcause == AST_CAUSE_INVALID_NUMBER_FORMAT) {
01900          res = AST_PBX_INCOMPLETE;
01901       }
01902 
01903       /* almost done, although the 'else' block is 400 lines */
01904    } else {
01905       const char *number;
01906 
01907       strcpy(pa.status, "ANSWER");
01908       pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
01909       /* Ah ha!  Someone answered within the desired timeframe.  Of course after this
01910          we will always return with -1 so that it is hung up properly after the
01911          conversation.  */
01912       hanguptree(outgoing, peer, 1);
01913       outgoing = NULL;
01914       /* If appropriate, log that we have a destination channel */
01915       if (chan->cdr)
01916          ast_cdr_setdestchan(chan->cdr, peer->name);
01917       if (peer->name)
01918          pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", peer->name);
01919       
01920       ast_channel_lock(peer);
01921       number = pbx_builtin_getvar_helper(peer, "DIALEDPEERNUMBER"); 
01922       if (!number)
01923          number = numsubst;
01924       pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", number);
01925       ast_channel_unlock(peer);
01926 
01927       if (!ast_strlen_zero(args.url) && ast_channel_supports_html(peer) ) {
01928          ast_debug(1, "app_dial: sendurl=%s.\n", args.url);
01929          ast_channel_sendurl( peer, args.url );
01930       }
01931       if ( (ast_test_flag64(&opts, OPT_PRIVACY) || ast_test_flag64(&opts, OPT_SCREENING)) && pa.privdb_val == AST_PRIVACY_UNKNOWN) {
01932          if (do_privacy(chan, peer, &opts, opt_args, &pa)) {
01933             res = 0;
01934             goto out;
01935          }
01936       }
01937       if (!ast_test_flag64(&opts, OPT_ANNOUNCE) || ast_strlen_zero(opt_args[OPT_ARG_ANNOUNCE])) {
01938          res = 0;
01939       } else {
01940          int digit = 0;
01941          struct ast_channel *chans[2];
01942          struct ast_channel *active_chan;
01943 
01944          chans[0] = chan;
01945          chans[1] = peer;
01946 
01947          /* we need to stream the announcment while monitoring the caller for a hangup */
01948 
01949          /* stream the file */
01950          res = ast_streamfile(peer, opt_args[OPT_ARG_ANNOUNCE], peer->language);
01951          if (res) {
01952             res = 0;
01953             ast_log(LOG_ERROR, "error streaming file '%s' to callee\n", opt_args[OPT_ARG_ANNOUNCE]);
01954          }
01955 
01956          ast_set_flag(peer, AST_FLAG_END_DTMF_ONLY);
01957          while (peer->stream) {
01958             int ms;
01959 
01960             ms = ast_sched_wait(peer->sched);
01961 
01962             if (ms < 0 && !peer->timingfunc) {
01963                ast_stopstream(peer);
01964                break;
01965             }
01966             if (ms < 0)
01967                ms = 1000;
01968 
01969             active_chan = ast_waitfor_n(chans, 2, &ms);
01970             if (active_chan) {
01971                struct ast_frame *fr = ast_read(active_chan);
01972                if (!fr) {
01973                   ast_hangup(peer);
01974                   res = -1;
01975                   goto done;
01976                }
01977                switch(fr->frametype) {
01978                   case AST_FRAME_DTMF_END:
01979                      digit = fr->subclass;
01980                      if (active_chan == peer && strchr(AST_DIGIT_ANY, res)) {
01981                         ast_stopstream(peer);
01982                         res = ast_senddigit(chan, digit, 0);
01983                      }
01984                      break;
01985                   case AST_FRAME_CONTROL:
01986                      switch (fr->subclass) {
01987                         case AST_CONTROL_HANGUP:
01988                            ast_frfree(fr);
01989                            ast_hangup(peer);
01990                            res = -1;
01991                            goto done;
01992                         default:
01993                            break;
01994                      }
01995                      break;
01996                   default:
01997                      /* Ignore all others */
01998                      break;
01999                }
02000                ast_frfree(fr);
02001             }
02002             ast_sched_runq(peer->sched);
02003          }
02004          ast_clear_flag(peer, AST_FLAG_END_DTMF_ONLY);
02005       }
02006 
02007       if (chan && peer && ast_test_flag64(&opts, OPT_GOTO) && !ast_strlen_zero(opt_args[OPT_ARG_GOTO])) {
02008          replace_macro_delimiter(opt_args[OPT_ARG_GOTO]);
02009          ast_parseable_goto(chan, opt_args[OPT_ARG_GOTO]);
02010          /* peer goes to the same context and extension as chan, so just copy info from chan*/
02011          ast_copy_string(peer->context, chan->context, sizeof(peer->context));
02012          ast_copy_string(peer->exten, chan->exten, sizeof(peer->exten));
02013          peer->priority = chan->priority + 2;
02014          ast_pbx_start(peer);
02015          hanguptree(outgoing, NULL, ast_test_flag64(&opts, OPT_CANCEL_ELSEWHERE) ? 1 : 0);
02016          if (continue_exec)
02017             *continue_exec = 1;
02018          res = 0;
02019          goto done;
02020       }
02021 
02022       if (ast_test_flag64(&opts, OPT_CALLEE_MACRO) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_MACRO])) {
02023          struct ast_app *theapp;
02024          const char *macro_result;
02025 
02026          res = ast_autoservice_start(chan);
02027          if (res) {
02028             ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
02029             res = -1;
02030          }
02031 
02032          theapp = pbx_findapp("Macro");
02033 
02034          if (theapp && !res) { /* XXX why check res here ? */
02035             /* Set peer->exten and peer->context so that MACRO_EXTEN and MACRO_CONTEXT get set */
02036             ast_copy_string(peer->context, chan->context, sizeof(peer->context));
02037             ast_copy_string(peer->exten, chan->exten, sizeof(peer->exten));
02038 
02039             replace_macro_delimiter(opt_args[OPT_ARG_CALLEE_MACRO]);
02040             res = pbx_exec(peer, theapp, opt_args[OPT_ARG_CALLEE_MACRO]);
02041             ast_debug(1, "Macro exited with status %d\n", res);
02042             res = 0;
02043          } else {
02044             ast_log(LOG_ERROR, "Could not find application Macro\n");
02045             res = -1;
02046          }
02047 
02048          if (ast_autoservice_stop(chan) < 0) {
02049             res = -1;
02050          }
02051 
02052          ast_channel_lock(peer);
02053 
02054          if (!res && (macro_result = pbx_builtin_getvar_helper(peer, "MACRO_RESULT"))) {
02055             char *macro_transfer_dest;
02056 
02057             if (!strcasecmp(macro_result, "BUSY")) {
02058                ast_copy_string(pa.status, macro_result, sizeof(pa.status));
02059                ast_set_flag64(peerflags, OPT_GO_ON);
02060                res = -1;
02061             } else if (!strcasecmp(macro_result, "CONGESTION") || !strcasecmp(macro_result, "CHANUNAVAIL")) {
02062                ast_copy_string(pa.status, macro_result, sizeof(pa.status));
02063                ast_set_flag64(peerflags, OPT_GO_ON);
02064                res = -1;
02065             } else if (!strcasecmp(macro_result, "CONTINUE")) {
02066                /* hangup peer and keep chan alive assuming the macro has changed
02067                   the context / exten / priority or perhaps
02068                   the next priority in the current exten is desired.
02069                */
02070                ast_set_flag64(peerflags, OPT_GO_ON);
02071                res = -1;
02072             } else if (!strcasecmp(macro_result, "ABORT")) {
02073                /* Hangup both ends unless the caller has the g flag */
02074                res = -1;
02075             } else if (!strncasecmp(macro_result, "GOTO:", 5) && (macro_transfer_dest = ast_strdupa(macro_result + 5))) {
02076                res = -1;
02077                /* perform a transfer to a new extension */
02078                if (strchr(macro_transfer_dest, '^')) { /* context^exten^priority*/
02079                   replace_macro_delimiter(macro_transfer_dest);
02080                   if (!ast_parseable_goto(chan, macro_transfer_dest))
02081                      ast_set_flag64(peerflags, OPT_GO_ON);
02082                }
02083             }
02084          }
02085 
02086          ast_channel_unlock(peer);
02087       }
02088 
02089       if (ast_test_flag64(&opts, OPT_CALLEE_GOSUB) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GOSUB])) {
02090          struct ast_app *theapp;
02091          const char *gosub_result;
02092          char *gosub_args, *gosub_argstart;
02093          int res9 = -1;
02094 
02095          res9 = ast_autoservice_start(chan);
02096          if (res9) {
02097             ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
02098             res9 = -1;
02099          }
02100 
02101          theapp = pbx_findapp("Gosub");
02102 
02103          if (theapp && !res9) {
02104             replace_macro_delimiter(opt_args[OPT_ARG_CALLEE_GOSUB]);
02105 
02106             /* Set where we came from */
02107             ast_copy_string(peer->context, "app_dial_gosub_virtual_context", sizeof(peer->context));
02108             ast_copy_string(peer->exten, "s", sizeof(peer->exten));
02109             peer->priority = 0;
02110 
02111             gosub_argstart = strchr(opt_args[OPT_ARG_CALLEE_GOSUB], ',');
02112             if (gosub_argstart) {
02113                *gosub_argstart = 0;
02114                if (asprintf(&gosub_args, "%s,s,1(%s)", opt_args[OPT_ARG_CALLEE_GOSUB], gosub_argstart + 1) < 0) {
02115                   ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
02116                   gosub_args = NULL;
02117                }
02118                *gosub_argstart = ',';
02119             } else {
02120                if (asprintf(&gosub_args, "%s,s,1", opt_args[OPT_ARG_CALLEE_GOSUB]) < 0) {
02121                   ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
02122                   gosub_args = NULL;
02123                }
02124             }
02125 
02126             if (gosub_args) {
02127                res9 = pbx_exec(peer, theapp, gosub_args);
02128                if (!res9) {
02129                   struct ast_pbx_args args;
02130                   /* A struct initializer fails to compile for this case ... */
02131                   memset(&args, 0, sizeof(args));
02132                   args.no_hangup_chan = 1;
02133                   ast_pbx_run_args(peer, &args);
02134                }
02135                ast_free(gosub_args);
02136                ast_debug(1, "Gosub exited with status %d\n", res9);
02137             } else {
02138                ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n");
02139             }
02140 
02141          } else if (!res9) {
02142             ast_log(LOG_ERROR, "Could not find application Gosub\n");
02143             res9 = -1;
02144          }
02145 
02146          if (ast_autoservice_stop(chan) < 0) {
02147             ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
02148             res9 = -1;
02149          }
02150          
02151          ast_channel_lock(peer);
02152 
02153          if (!res9 && (gosub_result = pbx_builtin_getvar_helper(peer, "GOSUB_RESULT"))) {
02154             char *gosub_transfer_dest;
02155 
02156             if (!strcasecmp(gosub_result, "BUSY")) {
02157                ast_copy_string(pa.status, gosub_result, sizeof(pa.status));
02158                ast_set_flag64(peerflags, OPT_GO_ON);
02159                res = -1;
02160             } else if (!strcasecmp(gosub_result, "CONGESTION") || !strcasecmp(gosub_result, "CHANUNAVAIL")) {
02161                ast_copy_string(pa.status, gosub_result, sizeof(pa.status));
02162                ast_set_flag64(peerflags, OPT_GO_ON);
02163                res = -1;
02164             } else if (!strcasecmp(gosub_result, "CONTINUE")) {
02165                /* hangup peer and keep chan alive assuming the macro has changed
02166                   the context / exten / priority or perhaps
02167                   the next priority in the current exten is desired.
02168                */
02169                ast_set_flag64(peerflags, OPT_GO_ON);
02170                res = -1;
02171             } else if (!strcasecmp(gosub_result, "ABORT")) {
02172                /* Hangup both ends unless the caller has the g flag */
02173                res = -1;
02174             } else if (!strncasecmp(gosub_result, "GOTO:", 5) && (gosub_transfer_dest = ast_strdupa(gosub_result + 5))) {
02175                res = -1;
02176                /* perform a transfer to a new extension */
02177                if (strchr(gosub_transfer_dest, '^')) { /* context^exten^priority*/
02178                   replace_macro_delimiter(gosub_transfer_dest);
02179                   if (!ast_parseable_goto(chan, gosub_transfer_dest))
02180                      ast_set_flag64(peerflags, OPT_GO_ON);
02181                }
02182             }
02183          }
02184 
02185          ast_channel_unlock(peer);  
02186       }
02187 
02188       if (!res) {
02189          if (!ast_tvzero(calldurationlimit)) {
02190             struct timeval whentohangup = calldurationlimit;
02191             peer->whentohangup = ast_tvadd(ast_tvnow(), whentohangup);
02192          }
02193          if (!ast_strlen_zero(dtmfcalled)) {
02194             ast_verb(3, "Sending DTMF '%s' to the called party.\n", dtmfcalled);
02195             res = ast_dtmf_stream(peer, chan, dtmfcalled, 250, 0);
02196          }
02197          if (!ast_strlen_zero(dtmfcalling)) {
02198             ast_verb(3, "Sending DTMF '%s' to the calling party.\n", dtmfcalling);
02199             res = ast_dtmf_stream(chan, peer, dtmfcalling, 250, 0);
02200          }
02201       }
02202 
02203       if (res) { /* some error */
02204          res = -1;
02205       } else {
02206          if (ast_test_flag64(peerflags, OPT_CALLEE_TRANSFER))
02207             ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
02208          if (ast_test_flag64(peerflags, OPT_CALLER_TRANSFER))
02209             ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
02210          if (ast_test_flag64(peerflags, OPT_CALLEE_HANGUP))
02211             ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
02212          if (ast_test_flag64(peerflags, OPT_CALLER_HANGUP))
02213             ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
02214          if (ast_test_flag64(peerflags, OPT_CALLEE_MONITOR))
02215             ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
02216          if (ast_test_flag64(peerflags, OPT_CALLER_MONITOR))
02217             ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
02218          if (ast_test_flag64(peerflags, OPT_CALLEE_PARK))
02219             ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
02220          if (ast_test_flag64(peerflags, OPT_CALLER_PARK))
02221             ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
02222          if (ast_test_flag64(peerflags, OPT_CALLEE_MIXMONITOR))
02223             ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMIXMON);
02224          if (ast_test_flag64(peerflags, OPT_CALLER_MIXMONITOR))
02225             ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMIXMON);
02226          if (ast_test_flag64(peerflags, OPT_GO_ON))
02227             ast_set_flag(&(config.features_caller), AST_FEATURE_NO_H_EXTEN);
02228 
02229          config.end_bridge_callback = end_bridge_callback;
02230          config.end_bridge_callback_data = chan;
02231          config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
02232          
02233          if (moh) {
02234             moh = 0;
02235             ast_moh_stop(chan);
02236          } else if (sentringing) {
02237             sentringing = 0;
02238             ast_indicate(chan, -1);
02239          }
02240          /* Be sure no generators are left on it */
02241          ast_deactivate_generator(chan);
02242          /* Make sure channels are compatible */
02243          res = ast_channel_make_compatible(chan, peer);
02244          if (res < 0) {
02245             ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", chan->name, peer->name);
02246             ast_hangup(peer);
02247             res = -1;
02248             goto done;
02249          }
02250          if (opermode) {
02251             struct oprmode oprmode;
02252 
02253             oprmode.peer = peer;
02254             oprmode.mode = opermode;
02255 
02256             ast_channel_setoption(chan, AST_OPTION_OPRMODE, &oprmode, sizeof(oprmode), 0);
02257          }
02258          res = ast_bridge_call(chan, peer, &config);
02259       }
02260 
02261       strcpy(peer->context, chan->context);
02262 
02263       if (ast_test_flag64(&opts, OPT_PEER_H) && ast_exists_extension(peer, peer->context, "h", 1, peer->cid.cid_num)) {
02264          int autoloopflag;
02265          int found;
02266          int res9;
02267          
02268          strcpy(peer->exten, "h");
02269          peer->priority = 1;
02270          autoloopflag = ast_test_flag(peer, AST_FLAG_IN_AUTOLOOP); /* save value to restore at the end */
02271          ast_set_flag(peer, AST_FLAG_IN_AUTOLOOP);
02272 
02273          while ((res9 = ast_spawn_extension(peer, peer->context, peer->exten, peer->priority, peer->cid.cid_num, &found, 1)) == 0)
02274             peer->priority++;
02275 
02276          if (found && res9) {
02277             /* Something bad happened, or a hangup has been requested. */
02278             ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", peer->context, peer->exten, peer->priority, peer->name);
02279             ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", peer->context, peer->exten, peer->priority, peer->name);
02280          }
02281          ast_set2_flag(peer, autoloopflag, AST_FLAG_IN_AUTOLOOP);  /* set it back the way it was */
02282       }
02283       if (!ast_check_hangup(peer) && ast_test_flag64(&opts, OPT_CALLEE_GO_ON) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GO_ON])) {      
02284          replace_macro_delimiter(opt_args[OPT_ARG_CALLEE_GO_ON]);
02285          ast_parseable_goto(peer, opt_args[OPT_ARG_CALLEE_GO_ON]);
02286          ast_pbx_start(peer);
02287       } else {
02288          if (!ast_check_hangup(chan))
02289             chan->hangupcause = peer->hangupcause;
02290          ast_hangup(peer);
02291       }
02292    }
02293 out:
02294    if (moh) {
02295       moh = 0;
02296       ast_moh_stop(chan);
02297    } else if (sentringing) {
02298       sentringing = 0;
02299       ast_indicate(chan, -1);
02300    }
02301 
02302    if (delprivintro && ast_fileexists(pa.privintro, NULL, NULL) > 0) {
02303       ast_filedelete(pa.privintro, NULL);
02304       if (ast_fileexists(pa.privintro, NULL, NULL) > 0) {
02305          ast_log(LOG_NOTICE, "privacy: ast_filedelete didn't do its job on %s\n", pa.privintro);
02306       } else {
02307          ast_verb(3, "Successfully deleted %s intro file\n", pa.privintro);
02308       }
02309    }
02310 
02311    ast_channel_early_bridge(chan, NULL);
02312    hanguptree(outgoing, NULL, 0); /* In this case, there's no answer anywhere */
02313    pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
02314    senddialendevent(chan, pa.status);
02315    ast_debug(1, "Exiting with DIALSTATUS=%s.\n", pa.status);
02316    
02317    if ((ast_test_flag64(peerflags, OPT_GO_ON)) && !ast_check_hangup(chan) && (res != AST_PBX_INCOMPLETE)) {
02318       if (!ast_tvzero(calldurationlimit))
02319          memset(&chan->whentohangup, 0, sizeof(chan->whentohangup));
02320       res = 0;
02321    }
02322 
02323 done:
02324    if (config.warning_sound) {
02325       ast_free((char *)config.warning_sound);
02326    }
02327    if (config.end_sound) {
02328       ast_free((char *)config.end_sound);
02329    }
02330    if (config.start_sound) {
02331       ast_free((char *)config.start_sound);
02332    }
02333    return res;
02334 }

static void do_forward ( struct chanlist o,
struct cause_args num,
struct ast_flags64 peerflags,
int  single 
) [static]

helper function for wait_for_answer()

XXX this code is highly suspicious, as it essentially overwrites the outgoing channel without properly deleting it.

Definition at line 712 of file app_dial.c.

References ast_channel::accountcode, accountcode, ast_call(), AST_CAUSE_BUSY, ast_channel_datastore_inherit(), ast_channel_inherit_variables(), ast_channel_lock, ast_channel_make_compatible(), ast_channel_unlock, ast_clear_flag64, ast_copy_string(), ast_hangup(), ast_indicate(), ast_log(), AST_MAX_EXTENSION, ast_request(), ast_rtp_make_compatible(), ast_set_callerid(), ast_strdup, ast_string_field_set, ast_strlen_zero(), ast_test_flag64, ast_verb, ast_channel::call_forward, CAN_EARLY_BRIDGE, cause, ast_channel::cdrflags, cause_args::chan, chanlist::chan, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_name, ast_callerid::cid_num, ast_callerid::cid_rdnis, ast_channel::context, DIAL_STILLGOING, ast_channel::exten, get_cid_name(), handle_cause(), LOG_NOTICE, ast_channel::macroexten, ast_channel::name, ast_channel::nativeformats, cause_args::nochan, OPT_FORCECLID, OPT_IGNORE_FORWARDING, OPT_ORIGINAL_CLID, pbx_builtin_getvar_helper(), S_OR, S_REPLACE, senddialevent(), and ast_channel::tech.

Referenced by wait_for_answer().

00714 {
00715    char tmpchan[256];
00716    struct ast_channel *original = o->chan;
00717    struct ast_channel *c = o->chan; /* the winner */
00718    struct ast_channel *in = num->chan; /* the input channel */
00719    char *stuff;
00720    char *tech;
00721    int cause;
00722 
00723    ast_copy_string(tmpchan, c->call_forward, sizeof(tmpchan));
00724    if ((stuff = strchr(tmpchan, '/'))) {
00725       *stuff++ = '\0';
00726       tech = tmpchan;
00727    } else {
00728       const char *forward_context;
00729       ast_channel_lock(c);
00730       forward_context = pbx_builtin_getvar_helper(c, "FORWARD_CONTEXT");
00731       if (ast_strlen_zero(forward_context)) {
00732          forward_context = NULL;
00733       }
00734       snprintf(tmpchan, sizeof(tmpchan), "%s@%s", c->call_forward, forward_context ? forward_context : c->context);
00735       ast_channel_unlock(c);
00736       stuff = tmpchan;
00737       tech = "Local";
00738    }
00739    /* Before processing channel, go ahead and check for forwarding */
00740    ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, c->name);
00741    /* If we have been told to ignore forwards, just set this channel to null and continue processing extensions normally */
00742    if (ast_test_flag64(peerflags, OPT_IGNORE_FORWARDING)) {
00743       ast_verb(3, "Forwarding %s to '%s/%s' prevented.\n", in->name, tech, stuff);
00744       c = o->chan = NULL;
00745       cause = AST_CAUSE_BUSY;
00746    } else {
00747       /* Setup parameters */
00748       c = o->chan = ast_request(tech, in->nativeformats, stuff, &cause);
00749       if (c) {
00750          if (single)
00751             ast_channel_make_compatible(o->chan, in);
00752          ast_channel_inherit_variables(in, o->chan);
00753          ast_channel_datastore_inherit(in, o->chan);
00754       } else
00755          ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
00756    }
00757    if (!c) {
00758       ast_clear_flag64(o, DIAL_STILLGOING);
00759       handle_cause(cause, num);
00760       ast_hangup(original);
00761    } else {
00762       char *new_cid_num, *new_cid_name;
00763       struct ast_channel *src;
00764 
00765       if (CAN_EARLY_BRIDGE(peerflags, c, in)) {
00766          ast_rtp_make_compatible(c, in, single);
00767       }
00768       if (ast_test_flag64(o, OPT_FORCECLID)) {
00769          new_cid_num = ast_strdup(S_OR(in->macroexten, in->exten));
00770          new_cid_name = NULL; /* XXX no name ? */
00771          src = c; /* XXX possible bug in previous code, which used 'winner' ? it may have changed */
00772       } else {
00773          new_cid_num = ast_strdup(in->cid.cid_num);
00774          new_cid_name = ast_strdup(in->cid.cid_name);
00775          src = in;
00776       }
00777       ast_string_field_set(c, accountcode, src->accountcode);
00778       c->cdrflags = src->cdrflags;
00779       S_REPLACE(c->cid.cid_num, new_cid_num);
00780       S_REPLACE(c->cid.cid_name, new_cid_name);
00781 
00782       if (in->cid.cid_ani) { /* XXX or maybe unconditional ? */
00783          S_REPLACE(c->cid.cid_ani, ast_strdup(in->cid.cid_ani));
00784       }
00785       S_REPLACE(c->cid.cid_rdnis, ast_strdup(S_OR(in->macroexten, in->exten)));
00786       if (ast_call(c, tmpchan, 0)) {
00787          ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
00788          ast_clear_flag64(o, DIAL_STILLGOING);
00789          ast_hangup(original);
00790          ast_hangup(c);
00791          c = o->chan = NULL;
00792          num->nochan++;
00793       } else {
00794          senddialevent(in, c, stuff);
00795          /* After calling, set callerid to extension */
00796          if (!ast_test_flag64(peerflags, OPT_ORIGINAL_CLID)) {
00797             char cidname[AST_MAX_EXTENSION] = "";
00798             ast_set_callerid(c, S_OR(in->macroexten, in->exten), get_cid_name(cidname, sizeof(cidname), in), NULL);
00799          }
00800          /* Hangup the original channel now, in case we needed it */
00801          ast_hangup(original);
00802       }
00803       if (single) {
00804          ast_indicate(in, -1);
00805       }
00806    }
00807 }

static int do_timelimit ( struct ast_channel chan,
struct ast_bridge_config config,
char *  parse,
struct timeval *  calldurationlimit 
) [static]

Definition at line 1143 of file app_dial.c.

References ast_channel_lock, ast_channel_unlock, AST_FEATURE_PLAY_WARNING, ast_log(), ast_set_flag, ast_strdup, ast_strlen_zero(), ast_true(), ast_verb, ast_bridge_config::end_sound, ast_bridge_config::features_callee, ast_bridge_config::features_caller, LOG_WARNING, pbx_builtin_getvar_helper(), ast_bridge_config::play_warning, S_OR, ast_bridge_config::start_sound, ast_bridge_config::timelimit, var, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.

Referenced by dial_exec_full().

01145 {
01146    char *stringp = ast_strdupa(parse);
01147    char *limit_str, *warning_str, *warnfreq_str;
01148    const char *var;
01149    int play_to_caller = 0, play_to_callee = 0;
01150    int delta;
01151 
01152    limit_str = strsep(&stringp, ":");
01153    warning_str = strsep(&stringp, ":");
01154    warnfreq_str = strsep(&stringp, ":");
01155 
01156    config->timelimit = atol(limit_str);
01157    if (warning_str)
01158       config->play_warning = atol(warning_str);
01159    if (warnfreq_str)
01160       config->warning_freq = atol(warnfreq_str);
01161 
01162    if (!config->timelimit) {
01163       ast_log(LOG_WARNING, "Dial does not accept L(%s), hanging up.\n", limit_str);
01164       config->timelimit = config->play_warning = config->warning_freq = 0;
01165       config->warning_sound = NULL;
01166       return -1; /* error */
01167    } else if ( (delta = config->play_warning - config->timelimit) > 0) {
01168       int w = config->warning_freq;
01169 
01170       /* If the first warning is requested _after_ the entire call would end,
01171          and no warning frequency is requested, then turn off the warning. If
01172          a warning frequency is requested, reduce the 'first warning' time by
01173          that frequency until it falls within the call's total time limit.
01174          Graphically:
01175               timelim->|    delta        |<-playwarning
01176          0__________________|_________________|
01177                 | w  |    |    |    |
01178 
01179          so the number of intervals to cut is 1+(delta-1)/w
01180       */
01181 
01182       if (w == 0) {
01183          config->play_warning = 0;
01184       } else {
01185          config->play_warning -= w * ( 1 + (delta-1)/w );
01186          if (config->play_warning < 1)
01187             config->play_warning = config->warning_freq = 0;
01188       }
01189    }
01190    
01191    ast_channel_lock(chan);
01192 
01193    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER");
01194 
01195    play_to_caller = var ? ast_true(var) : 1;
01196 
01197    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE");
01198    play_to_callee = var ? ast_true(var) : 0;
01199 
01200    if (!play_to_caller && !play_to_callee)
01201       play_to_caller = 1;
01202 
01203    var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE");
01204    config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft");
01205 
01206    /* The code looking at config wants a NULL, not just "", to decide
01207     * that the message should not be played, so we replace "" with NULL.
01208     * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is
01209     * not found.
01210     */
01211 
01212    var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE");
01213    config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
01214 
01215    var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE");
01216    config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
01217 
01218    ast_channel_unlock(chan);
01219 
01220    /* undo effect of S(x) in case they are both used */
01221    calldurationlimit->tv_sec = 0;
01222    calldurationlimit->tv_usec = 0;
01223 
01224    /* more efficient to do it like S(x) does since no advanced opts */
01225    if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) {
01226       calldurationlimit->tv_sec = config->timelimit / 1000;
01227       calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000;
01228       ast_verb(3, "Setting call duration limit to %.3lf seconds.\n",
01229          calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0);
01230       config->timelimit = play_to_caller = play_to_callee =
01231       config->play_warning = config->warning_freq = 0;
01232    } else {
01233       ast_verb(3, "Limit Data for this call:\n");
01234       ast_verb(4, "timelimit      = %ld\n", config->timelimit);
01235       ast_verb(4, "play_warning   = %ld\n", config->play_warning);
01236       ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no");
01237       ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no");
01238       ast_verb(4, "warning_freq   = %ld\n", config->warning_freq);
01239       ast_verb(4, "start_sound    = %s\n", S_OR(config->start_sound, ""));
01240       ast_verb(4, "warning_sound  = %s\n", config->warning_sound);
01241       ast_verb(4, "end_sound      = %s\n", S_OR(config->end_sound, ""));
01242    }
01243    if (play_to_caller)
01244       ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
01245    if (play_to_callee)
01246       ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
01247    return 0;
01248 }

static void end_bridge_callback ( void *  data  )  [static]

Definition at line 1486 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 dial_exec_full().

01487 {
01488    char buf[80];
01489    time_t end;
01490    struct ast_channel *chan = data;
01491 
01492    if (!chan->cdr) {
01493       return;
01494    }
01495 
01496    time(&end);
01497 
01498    ast_channel_lock(chan);
01499    if (chan->cdr->answer.tv_sec) {
01500       snprintf(buf, sizeof(buf), "%ld", end - chan->cdr->answer.tv_sec);
01501       pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf);
01502    }
01503 
01504    if (chan->cdr->start.tv_sec) {
01505       snprintf(buf, sizeof(buf), "%ld", end - chan->cdr->start.tv_sec);
01506       pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf);
01507    }
01508    ast_channel_unlock(chan);
01509 }

static void end_bridge_callback_data_fixup ( struct ast_bridge_config bconfig,
struct ast_channel originator,
struct ast_channel terminator 
) [static]

Definition at line 1511 of file app_dial.c.

References ast_bridge_config::end_bridge_callback_data.

Referenced by dial_exec_full().

01511                                                                                                                                               {
01512    bconfig->end_bridge_callback_data = originator;
01513 }

static const char* get_cid_name ( char *  name,
int  namelen,
struct ast_channel chan 
) [static]

Definition at line 672 of file app_dial.c.

References ast_get_hint(), 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().

00673 {
00674    const char *context = S_OR(chan->macrocontext, chan->context);
00675    const char *exten = S_OR(chan->macroexten, chan->exten);
00676 
00677    return ast_get_hint(NULL, 0, name, namelen, chan, context, exten) ? name : "";
00678 }

static void handle_cause ( int  cause,
struct cause_args num 
) [static]

Definition at line 607 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 dial_exec_full(), do_forward(), and wait_for_answer().

00608 {
00609    struct ast_cdr *cdr = num->chan->cdr;
00610 
00611    switch(cause) {
00612    case AST_CAUSE_BUSY:
00613       if (cdr)
00614          ast_cdr_busy(cdr);
00615       num->busy++;
00616       break;
00617 
00618    case AST_CAUSE_CONGESTION:
00619       if (cdr)
00620          ast_cdr_failed(cdr);
00621       num->congestion++;
00622       break;
00623 
00624    case AST_CAUSE_NO_ROUTE_DESTINATION:
00625    case AST_CAUSE_UNREGISTERED:
00626       if (cdr)
00627          ast_cdr_failed(cdr);
00628       num->nochan++;
00629       break;
00630 
00631    case AST_CAUSE_NO_ANSWER:
00632       if (cdr) {
00633          ast_cdr_noanswer(cdr);
00634       }
00635       break;
00636    case AST_CAUSE_NORMAL_CLEARING:
00637       break;
00638 
00639    default:
00640       num->nochan++;
00641       break;
00642    }
00643 }

static void hanguptree ( struct chanlist outgoing,
struct ast_channel exception,
int  answered_elsewhere 
) [static]

Definition at line 574 of file app_dial.c.

References AST_CAUSE_ANSWERED_ELSEWHERE, AST_FLAG_ANSWERED_ELSEWHERE, ast_free, ast_hangup(), ast_set_flag, chanlist::chan, ast_channel::hangupcause, and chanlist::next.

Referenced by dial_exec_full().

00575 {
00576    /* Hang up a tree of stuff */
00577    struct chanlist *oo;
00578    while (outgoing) {
00579       /* Hangup any existing lines we have open */
00580       if (outgoing->chan && (outgoing->chan != exception)) {
00581          if (answered_elsewhere) {
00582             /* The flag is used for local channel inheritance and stuff */
00583             ast_set_flag(outgoing->chan, AST_FLAG_ANSWERED_ELSEWHERE);
00584             /* This is for the channel drivers */
00585             outgoing->chan->hangupcause = AST_CAUSE_ANSWERED_ELSEWHERE;
00586          }
00587          ast_hangup(outgoing->chan);
00588       }
00589       oo = outgoing;
00590       outgoing = outgoing->next;
00591       ast_free(oo);
00592    }
00593 }

static int load_module ( void   )  [static]

Definition at line 2469 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().

02470 {
02471    int res;
02472    struct ast_context *con;
02473 
02474    con = ast_context_find_or_create(NULL, NULL, "app_dial_gosub_virtual_context", "app_dial");
02475    if (!con)
02476       ast_log(LOG_ERROR, "Dial virtual context 'app_dial_gosub_virtual_context' does not exist and unable to create\n");
02477    else
02478       ast_add_extension2(con, 1, "s", 1, NULL, NULL, "NoOp", ast_strdup(""), ast_free_ptr, "app_dial");
02479 
02480    res = ast_register_application_xml(app, dial_exec);
02481    res |= ast_register_application_xml(rapp, retrydial_exec);
02482 
02483    return res;
02484 }

static int onedigit_goto ( struct ast_channel chan,
const char *  context,
char  exten,
int  pri 
) [static]

Definition at line 653 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().

00654 {
00655    char rexten[2] = { exten, '\0' };
00656 
00657    if (context) {
00658       if (!ast_goto_if_exists(chan, context, rexten, pri))
00659          return 1;
00660    } else {
00661       if (!ast_goto_if_exists(chan, chan->context, rexten, pri))
00662          return 1;
00663       else if (!ast_strlen_zero(chan->macrocontext)) {
00664          if (!ast_goto_if_exists(chan, chan->macrocontext, rexten, pri))
00665             return 1;
00666       }
00667    }
00668    return 0;
00669 }

static void replace_macro_delimiter ( char *  s  )  [static]

Definition at line 1124 of file app_dial.c.

Referenced by dial_exec_full().

01125 {
01126    for (; *s; s++)
01127       if (*s == '^')
01128          *s = ',';
01129 }

static int retrydial_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 2345 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_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().

02346 {
02347    char *parse;
02348    const char *context = NULL;
02349    int sleepms = 0, loops = 0, res = -1;
02350    struct ast_flags64 peerflags = { 0, };
02351    AST_DECLARE_APP_ARGS(args,
02352       AST_APP_ARG(announce);
02353       AST_APP_ARG(sleep);
02354       AST_APP_ARG(retries);
02355       AST_APP_ARG(dialdata);
02356    );
02357 
02358    if (ast_strlen_zero(data)) {
02359       ast_log(LOG_WARNING, "RetryDial requires an argument!\n");
02360       return -1;
02361    }
02362 
02363    parse = ast_strdupa(data);
02364    AST_STANDARD_APP_ARGS(args, parse);
02365 
02366    if (!ast_strlen_zero(args.sleep) && (sleepms = atoi(args.sleep)))
02367       sleepms *= 1000;
02368 
02369    if (!ast_strlen_zero(args.retries)) {
02370       loops = atoi(args.retries);
02371    }
02372 
02373    if (!args.dialdata) {
02374       ast_log(LOG_ERROR, "%s requires a 4th argument (dialdata)\n", rapp);
02375       goto done;
02376    }
02377 
02378    if (sleepms < 1000)
02379       sleepms = 10000;
02380 
02381    if (!loops)
02382       loops = -1; /* run forever */
02383 
02384    ast_channel_lock(chan);
02385    context = pbx_builtin_getvar_helper(chan, "EXITCONTEXT");
02386    context = !ast_strlen_zero(context) ? ast_strdupa(context) : NULL;
02387    ast_channel_unlock(chan);
02388 
02389    res = 0;
02390    while (loops) {
02391       int continue_exec;
02392 
02393       chan->data = "Retrying";
02394       if (ast_test_flag(chan, AST_FLAG_MOH))
02395          ast_moh_stop(chan);
02396 
02397       res = dial_exec_full(chan, args.dialdata, &peerflags, &continue_exec);
02398       if (continue_exec)
02399          break;
02400 
02401       if (res == 0) {
02402          if (ast_test_flag64(&peerflags, OPT_DTMF_EXIT)) {
02403             if (!ast_strlen_zero(args.announce)) {
02404                if (ast_fileexists(args.announce, NULL, chan->language) > 0) {
02405                   if (!(res = ast_streamfile(chan, args.announce, chan->language)))
02406                      ast_waitstream(chan, AST_DIGIT_ANY);
02407                } else
02408                   ast_log(LOG_WARNING, "Announce file \"%s\" specified in Retrydial does not exist\n", args.announce);
02409             }
02410             if (!res && sleepms) {
02411                if (!ast_test_flag(chan, AST_FLAG_MOH))
02412                   ast_moh_start(chan, NULL, NULL);
02413                res = ast_waitfordigit(chan, sleepms);
02414             }
02415          } else {
02416             if (!ast_strlen_zero(args.announce)) {
02417                if (ast_fileexists(args.announce, NULL, chan->language) > 0) {
02418                   if (!(res = ast_streamfile(chan, args.announce, chan->language)))
02419                      res = ast_waitstream(chan, "");
02420                } else
02421                   ast_log(LOG_WARNING, "Announce file \"%s\" specified in Retrydial does not exist\n", args.announce);
02422             }
02423             if (sleepms) {
02424                if (!ast_test_flag(chan, AST_FLAG_MOH))
02425                   ast_moh_start(chan, NULL, NULL);
02426                if (!res)
02427                   res = ast_waitfordigit(chan, sleepms);
02428             }
02429          }
02430       }
02431 
02432       if (res < 0 || res == AST_PBX_INCOMPLETE) {
02433          break;
02434       } else if (res > 0) { /* Trying to send the call elsewhere (1 digit ext) */
02435          if (onedigit_goto(chan, context, (char) res, 1)) {
02436             res = 0;
02437             break;
02438          }
02439       }
02440       loops--;
02441    }
02442    if (loops == 0)
02443       res = 0;
02444    else if (res == 1)
02445       res = 0;
02446 
02447    if (ast_test_flag(chan, AST_FLAG_MOH))
02448       ast_moh_stop(chan);
02449  done:
02450    return res;
02451 }

static void senddialendevent ( const struct ast_channel src,
const char *  dialstatus 
) [static]

Definition at line 696 of file app_dial.c.

References EVENT_FLAG_CALL, manager_event, ast_channel::name, and ast_channel::uniqueid.

Referenced by dial_exec_full().

00697 {
00698    manager_event(EVENT_FLAG_CALL, "Dial",
00699       "SubEvent: End\r\n"
00700       "Channel: %s\r\n"
00701       "UniqueID: %s\r\n"
00702       "DialStatus: %s\r\n",
00703       src->name, src->uniqueid, dialstatus);
00704 }

static void senddialevent ( struct ast_channel src,
struct ast_channel dst,
const char *  dialstring 
) [static]

Definition at line 680 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().

00681 {
00682    manager_event(EVENT_FLAG_CALL, "Dial",
00683       "SubEvent: Begin\r\n"
00684       "Channel: %s\r\n"
00685       "Destination: %s\r\n"
00686       "CallerIDNum: %s\r\n"
00687       "CallerIDName: %s\r\n"
00688       "UniqueID: %s\r\n"
00689       "DestUniqueID: %s\r\n"
00690       "Dialstring: %s\r\n",
00691       src->name, dst->name, S_OR(src->cid.cid_num, "<unknown>"),
00692       S_OR(src->cid.cid_name, "<unknown>"), src->uniqueid,
00693       dst->uniqueid, dialstring ? dialstring : "");
00694 }

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 1385 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_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_NOCLID, privacy_args::privcid, privacy_args::privdb_val, privacy_args::privintro, silencethreshold, privacy_args::status, and THRESHOLD_SILENCE.

Referenced by dial_exec_full().

01387 {
01388    char callerid[60];
01389    int res;
01390    char *l;
01391    int silencethreshold;
01392 
01393    if (!ast_strlen_zero(chan->cid.cid_num)) {
01394       l = ast_strdupa(chan->cid.cid_num);
01395       ast_shrink_phone_number(l);
01396       if (ast_test_flag64(opts, OPT_PRIVACY) ) {
01397          ast_verb(3, "Privacy DB is '%s', clid is '%s'\n", opt_args[OPT_ARG_PRIVACY], l);
01398          pa->privdb_val = ast_privacy_check(opt_args[OPT_ARG_PRIVACY], l);
01399       } else {
01400          ast_verb(3, "Privacy Screening, clid is '%s'\n", l);
01401          pa->privdb_val = AST_PRIVACY_UNKNOWN;
01402       }
01403    } else {
01404       char *tnam, *tn2;
01405 
01406       tnam = ast_strdupa(chan->name);
01407       /* clean the channel name so slashes don't try to end up in disk file name */
01408       for (tn2 = tnam; *tn2; tn2++) {
01409          if (*tn2 == '/')  /* any other chars to be afraid of? */
01410             *tn2 = '=';
01411       }
01412       ast_verb(3, "Privacy-- callerid is empty\n");
01413 
01414       snprintf(callerid, sizeof(callerid), "NOCALLERID_%s%s", chan->exten, tnam);
01415       l = callerid;
01416       pa->privdb_val = AST_PRIVACY_UNKNOWN;
01417    }
01418 
01419    ast_copy_string(pa->privcid, l, sizeof(pa->privcid));
01420 
01421    if (strncmp(pa->privcid, "NOCALLERID", 10) != 0 && ast_test_flag64(opts, OPT_SCREEN_NOCLID)) {
01422       /* if callerid is set and OPT_SCREEN_NOCLID is set also */
01423       ast_verb(3, "CallerID set (%s); N option set; Screening should be off\n", pa->privcid);
01424       pa->privdb_val = AST_PRIVACY_ALLOW;
01425    } else if (ast_test_flag64(opts, OPT_SCREEN_NOCLID) && strncmp(pa->privcid, "NOCALLERID", 10) == 0) {
01426       ast_verb(3, "CallerID blank; N option set; Screening should happen; dbval is %d\n", pa->privdb_val);
01427    }
01428    
01429    if (pa->privdb_val == AST_PRIVACY_DENY) {
01430       ast_verb(3, "Privacy DB reports PRIVACY_DENY for this callerid. Dial reports unavailable\n");
01431       ast_copy_string(pa->status, "NOANSWER", sizeof(pa->status));
01432       return 0;
01433    } else if (pa->privdb_val == AST_PRIVACY_KILL) {
01434       ast_copy_string(pa->status, "DONTCALL", sizeof(pa->status));
01435       return 0; /* Is this right? */
01436    } else if (pa->privdb_val == AST_PRIVACY_TORTURE) {
01437       ast_copy_string(pa->status, "TORTURE", sizeof(pa->status));
01438       return 0; /* is this right??? */
01439    } else if (pa->privdb_val == AST_PRIVACY_UNKNOWN) {
01440       /* Get the user's intro, store it in priv-callerintros/$CID,
01441          unless it is already there-- this should be done before the
01442          call is actually dialed  */
01443 
01444       /* make sure the priv-callerintros dir actually exists */
01445       snprintf(pa->privintro, sizeof(pa->privintro), "%s/sounds/priv-callerintros", ast_config_AST_DATA_DIR);
01446       if ((res = ast_mkdir(pa->privintro, 0755))) {
01447          ast_log(LOG_WARNING, "privacy: can't create directory priv-callerintros: %s\n", strerror(res));
01448          return -1;
01449       }
01450 
01451       snprintf(pa->privintro, sizeof(pa->privintro), "priv-callerintros/%s", pa->privcid);
01452       if (ast_fileexists(pa->privintro, NULL, NULL ) > 0 && strncmp(pa->privcid, "NOCALLERID", 10) != 0) {
01453          /* the DELUX version of this code would allow this caller the
01454             option to hear and retape their previously recorded intro.
01455          */
01456       } else {
01457          int duration; /* for feedback from play_and_wait */
01458          /* the file doesn't exist yet. Let the caller submit his
01459             vocal intro for posterity */
01460          /* priv-recordintro script:
01461 
01462             "At the tone, please say your name:"
01463 
01464          */
01465          silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
01466          ast_answer(chan);
01467          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 */
01468                            /* don't think we'll need a lock removed, we took care of
01469                               conflicts by naming the pa.privintro file */
01470          if (res == -1) {
01471             /* Delete the file regardless since they hung up during recording */
01472             ast_filedelete(pa->privintro, NULL);
01473             if (ast_fileexists(pa->privintro, NULL, NULL) > 0)
01474                ast_log(LOG_NOTICE, "privacy: ast_filedelete didn't do its job on %s\n", pa->privintro);
01475             else
01476                ast_verb(3, "Successfully deleted %s intro file\n", pa->privintro);
01477             return -1;
01478          }
01479          if (!ast_streamfile(chan, "vm-dialout", chan->language) )
01480             ast_waitstream(chan, "");
01481       }
01482    }
01483    return 1; /* success */
01484 }

static int unload_module ( void   )  [static]

Definition at line 2453 of file app_dial.c.

References ast_context_destroy(), ast_context_find(), ast_context_remove_extension2(), and ast_unregister_application().

02454 {
02455    int res;
02456    struct ast_context *con;
02457 
02458    res = ast_unregister_application(app);
02459    res |= ast_unregister_application(rapp);
02460 
02461    if ((con = ast_context_find("app_dial_gosub_virtual_context"))) {
02462       ast_context_remove_extension2(con, "s", 1, NULL, 0);
02463       ast_context_destroy(con, "app_dial"); /* leave nothing behind */
02464    }
02465 
02466    return res;
02467 }

static int valid_priv_reply ( struct ast_flags64 opts,
int  res 
) [static]

Definition at line 1132 of file app_dial.c.

References ast_test_flag64, OPT_PRIVACY, and OPT_SCREENING.

01133 {
01134    if (res < '1')
01135       return 0;
01136    if (ast_test_flag64(opts, OPT_PRIVACY) && res <= '5')
01137       return 1;
01138    if (ast_test_flag64(opts, OPT_SCREENING) && res <= '4')
01139       return 1;
01140    return 0;
01141 }

static struct ast_channel* wait_for_answer ( struct ast_channel in,
struct chanlist outgoing,
int *  to,
struct ast_flags64 peerflags,
struct privacy_args pa,
const struct cause_args num_in,
int *  result 
) [static, read]

Definition at line 818 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_early_bridge(), ast_channel_lock, ast_channel_make_compatible(), ast_channel_sendhtml(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag64, AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OFFHOOK, AST_CONTROL_PROCEEDING, AST_CONTROL_PROGRESS, AST_CONTROL_RINGING, AST_CONTROL_SRCUPDATE, AST_CONTROL_UNHOLD, AST_CONTROL_VIDUPDATE, ast_copy_flags64, ast_copy_string(), ast_deactivate_generator(), ast_debug, AST_FRAME_CONTROL, AST_FRAME_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_poll_channel_add(), ast_poll_channel_del(), ast_read(), AST_STATE_UP, 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, cause_args::congestion, context, ast_frame::data, ast_frame::datalen, DIAL_NOFORWARDHTML, DIAL_STILLGOING, dialcontext, ast_cdr::disposition, do_forward(), ast_channel::exten, f, ast_frame::frametype, handle_cause(), ast_channel::hangupcause, LOG_WARNING, ast_channel::name, chanlist::next, cause_args::nochan, 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_MUSICBACK, OPT_RINGBACK, pbx_builtin_getvar_helper(), ast_frame::ptr, privacy_args::sentringing, privacy_args::status, ast_frame::subclass, and ast_frame::uint32.

Referenced by dial_exec_full().

00822 {
00823    struct cause_args num = *num_in;
00824    int prestart = num.busy + num.congestion + num.nochan;
00825    int orig = *to;
00826    struct ast_channel *peer = NULL;
00827    /* single is set if only one destination is enabled */
00828    int single = outgoing && !outgoing->next && !ast_test_flag64(outgoing, OPT_MUSICBACK | OPT_RINGBACK);
00829 #ifdef HAVE_EPOLL
00830    struct chanlist *epollo;
00831 #endif
00832 
00833    if (single) {
00834       /* Turn off hold music, etc */
00835       ast_deactivate_generator(in);
00836       /* If we are calling a single channel, make them compatible for in-band tone purpose */
00837       ast_channel_make_compatible(outgoing->chan, in);
00838    }
00839 
00840 #ifdef HAVE_EPOLL
00841    for (epollo = outgoing; epollo; epollo = epollo->next)
00842       ast_poll_channel_add(in, epollo->chan);
00843 #endif
00844 
00845    while (*to && !peer) {
00846       struct chanlist *o;
00847       int pos = 0; /* how many channels do we handle */
00848       int numlines = prestart;
00849       struct ast_channel *winner;
00850       struct ast_channel *watchers[AST_MAX_WATCHERS];
00851 
00852       watchers[pos++] = in;
00853       for (o = outgoing; o; o = o->next) {
00854          /* Keep track of important channels */
00855          if (ast_test_flag64(o, DIAL_STILLGOING) && o->chan)
00856             watchers[pos++] = o->chan;
00857          numlines++;
00858       }
00859       if (pos == 1) { /* only the input channel is available */
00860          if (numlines == (num.busy + num.congestion + num.nochan)) {
00861             ast_verb(2, "Everyone is busy/congested at this time (%d:%d/%d/%d)\n", numlines, num.busy, num.congestion, num.nochan);
00862             if (num.busy)
00863                strcpy(pa->status, "BUSY");
00864             else if (num.congestion)
00865                strcpy(pa->status, "CONGESTION");
00866             else if (num.nochan)
00867                strcpy(pa->status, "CHANUNAVAIL");
00868          } else {
00869             ast_verb(3, "No one is available to answer at this time (%d:%d/%d/%d)\n", numlines, num.busy, num.congestion, num.nochan);
00870          }
00871          *to = 0;
00872          return NULL;
00873       }
00874       winner = ast_waitfor_n(watchers, pos, to);
00875       for (o = outgoing; o; o = o->next) {
00876          struct ast_frame *f;
00877          struct ast_channel *c = o->chan;
00878 
00879          if (c == NULL)
00880             continue;
00881          if (ast_test_flag64(o, DIAL_STILLGOING) && c->_state == AST_STATE_UP) {
00882             if (!peer) {
00883                ast_verb(3, "%s answered %s\n", c->name, in->name);
00884                peer = c;
00885                ast_copy_flags64(peerflags, o,
00886                   OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
00887                   OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
00888                   OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
00889                   OPT_CALLEE_PARK | OPT_CALLER_PARK |
00890                   OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR |
00891                   DIAL_NOFORWARDHTML);
00892                ast_string_field_set(c, dialcontext, "");
00893                ast_copy_string(c->exten, "", sizeof(c->exten));
00894             }
00895             continue;
00896          }
00897          if (c != winner)
00898             continue;
00899          /* here, o->chan == c == winner */
00900          if (!ast_strlen_zero(c->call_forward)) {
00901             do_forward(o, &num, peerflags, single);
00902             continue;
00903          }
00904          f = ast_read(winner);
00905          if (!f) {
00906             in->hangupcause = c->hangupcause;
00907 #ifdef HAVE_EPOLL
00908             ast_poll_channel_del(in, c);
00909 #endif
00910             ast_hangup(c);
00911             c = o->chan = NULL;
00912             ast_clear_flag64(o, DIAL_STILLGOING);
00913             handle_cause(in->hangupcause, &num);
00914             continue;
00915          }
00916          if (f->frametype == AST_FRAME_CONTROL) {
00917             switch(f->subclass) {
00918             case AST_CONTROL_ANSWER:
00919                /* This is our guy if someone answered. */
00920                if (!peer) {
00921                   ast_verb(3, "%s answered %s\n", c->name, in->name);
00922                   peer = c;
00923                   if (peer->cdr) {
00924                      peer->cdr->answer = ast_tvnow();
00925                      peer->cdr->disposition = AST_CDR_ANSWERED;
00926                   }
00927                   ast_copy_flags64(peerflags, o,
00928                      OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
00929                      OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
00930                      OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
00931                      OPT_CALLEE_PARK | OPT_CALLER_PARK |
00932                      OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR |
00933                      DIAL_NOFORWARDHTML);
00934                   ast_string_field_set(c, dialcontext, "");
00935                   ast_copy_string(c->exten, "", sizeof(c->exten));
00936                   if (CAN_EARLY_BRIDGE(peerflags, in, peer))
00937                      /* Setup early bridge if appropriate */
00938                      ast_channel_early_bridge(in, peer);
00939                }
00940                /* If call has been answered, then the eventual hangup is likely to be normal hangup */
00941                in->hangupcause = AST_CAUSE_NORMAL_CLEARING;
00942                c->hangupcause = AST_CAUSE_NORMAL_CLEARING;
00943                break;
00944             case AST_CONTROL_BUSY:
00945                ast_verb(3, "%s is busy\n", c->name);
00946                in->hangupcause = c->hangupcause;
00947                ast_hangup(c);
00948                c = o->chan = NULL;
00949                ast_clear_flag64(o, DIAL_STILLGOING);
00950                handle_cause(AST_CAUSE_BUSY, &num);
00951                break;
00952             case AST_CONTROL_CONGESTION:
00953                ast_verb(3, "%s is circuit-busy\n", c->name);
00954                in->hangupcause = c->hangupcause;
00955                ast_hangup(c);
00956                c = o->chan = NULL;
00957                ast_clear_flag64(o, DIAL_STILLGOING);
00958                handle_cause(AST_CAUSE_CONGESTION, &num);
00959                break;
00960             case AST_CONTROL_RINGING:
00961                ast_verb(3, "%s is ringing\n", c->name);
00962                /* Setup early media if appropriate */
00963                if (single && CAN_EARLY_BRIDGE(peerflags, in, c))
00964                   ast_channel_early_bridge(in, c);
00965                if (!(pa->sentringing) && !ast_test_flag64(outgoing, OPT_MUSICBACK)) {
00966                   ast_indicate(in, AST_CONTROL_RINGING);
00967                   pa->sentringing++;
00968                }
00969                break;
00970             case AST_CONTROL_PROGRESS:
00971                ast_verb(3, "%s is making progress passing it to %s\n", c->name, in->name);
00972                /* Setup early media if appropriate */
00973                if (single && CAN_EARLY_BRIDGE(peerflags, in, c))
00974                   ast_channel_early_bridge(in, c);
00975                if (!ast_test_flag64(outgoing, OPT_RINGBACK))
00976                   if (single || (!single && !pa->sentringing)) {
00977                      ast_indicate(in, AST_CONTROL_PROGRESS);
00978                   }
00979                break;
00980             case AST_CONTROL_VIDUPDATE:
00981                ast_verb(3, "%s requested a video update, passing it to %s\n", c->name, in->name);
00982                ast_indicate(in, AST_CONTROL_VIDUPDATE);
00983                break;
00984             case AST_CONTROL_SRCUPDATE:
00985                ast_verb(3, "%s requested a source update, passing it to %s\n", c->name, in->name);
00986                ast_indicate(in, AST_CONTROL_SRCUPDATE);
00987                break;
00988             case AST_CONTROL_PROCEEDING:
00989                ast_verb(3, "%s is proceeding passing it to %s\n", c->name, in->name);
00990                if (single && CAN_EARLY_BRIDGE(peerflags, in, c))
00991                   ast_channel_early_bridge(in, c);
00992                if (!ast_test_flag64(outgoing, OPT_RINGBACK))
00993                   ast_indicate(in, AST_CONTROL_PROCEEDING);
00994                break;
00995             case AST_CONTROL_HOLD:
00996                ast_verb(3, "Call on %s placed on hold\n", c->name);
00997                ast_indicate(in, AST_CONTROL_HOLD);
00998                break;
00999             case AST_CONTROL_UNHOLD:
01000                ast_verb(3, "Call on %s left from hold\n", c->name);
01001                ast_indicate(in, AST_CONTROL_UNHOLD);
01002                break;
01003             case AST_CONTROL_OFFHOOK:
01004             case AST_CONTROL_FLASH:
01005                /* Ignore going off hook and flash */
01006                break;
01007             case -1:
01008                if (!ast_test_flag64(outgoing, OPT_RINGBACK | OPT_MUSICBACK)) {
01009                   ast_verb(3, "%s stopped sounds\n", c->name);
01010                   ast_indicate(in, -1);
01011                   pa->sentringing = 0;
01012                }
01013                break;
01014             default:
01015                ast_debug(1, "Dunno what to do with control type %d\n", f->subclass);
01016             }
01017          } else if (single) {
01018             switch (f->frametype) {
01019                case AST_FRAME_VOICE:
01020                case AST_FRAME_IMAGE:
01021                case AST_FRAME_TEXT:
01022                   if (ast_write(in, f)) {
01023                      ast_log(LOG_WARNING, "Unable to write frame\n");
01024                   }
01025                   break;
01026                case AST_FRAME_HTML:
01027                   if (!ast_test_flag64(outgoing, DIAL_NOFORWARDHTML) && ast_channel_sendhtml(in, f->subclass, f->data.ptr, f->datalen) == -1) {
01028                      ast_log(LOG_WARNING, "Unable to send URL\n");
01029                   }
01030                   break;
01031                default:
01032                   break;
01033             }
01034          }
01035          ast_frfree(f);
01036       } /* end for */
01037       if (winner == in) {
01038          struct ast_frame *f = ast_read(in);
01039 #if 0
01040          if (f && (f->frametype != AST_FRAME_VOICE))
01041             printf("Frame type: %d, %d\n", f->frametype, f->subclass);
01042          else if (!f || (f->frametype != AST_FRAME_VOICE))
01043             printf("Hangup received on %s\n", in->name);
01044 #endif
01045          if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
01046             /* Got hung up */
01047             *to = -1;
01048             strcpy(pa->status, "CANCEL");
01049             ast_cdr_noanswer(in->cdr);
01050             if (f) {
01051                if (f->data.uint32) {
01052                   in->hangupcause = f->data.uint32;
01053                }
01054                ast_frfree(f);
01055             }
01056             return NULL;
01057          }
01058 
01059          /* now f is guaranteed non-NULL */
01060          if (f->frametype == AST_FRAME_DTMF) {
01061             if (ast_test_flag64(peerflags, OPT_DTMF_EXIT)) {
01062                const char *context;
01063                ast_channel_lock(in);
01064                context = pbx_builtin_getvar_helper(in, "EXITCONTEXT");
01065                if (onedigit_goto(in, context, (char) f->subclass, 1)) {
01066                   ast_verb(3, "User hit %c to disconnect call.\n", f->subclass);
01067                   *to = 0;
01068                   ast_cdr_noanswer(in->cdr);
01069                   *result = f->subclass;
01070                   strcpy(pa->status, "CANCEL");
01071                   ast_frfree(f);
01072                   ast_channel_unlock(in);
01073                   return NULL;
01074                }
01075                ast_channel_unlock(in);
01076             }
01077 
01078             if (ast_test_flag64(peerflags, OPT_CALLER_HANGUP) &&
01079                   (f->subclass == '*')) { /* hmm it it not guaranteed to be '*' anymore. */
01080                ast_verb(3, "User hit %c to disconnect call.\n", f->subclass);
01081                *to = 0;
01082                strcpy(pa->status, "CANCEL");
01083                ast_cdr_noanswer(in->cdr);
01084                ast_frfree(f);
01085                return NULL;
01086             }
01087          }
01088 
01089          /* Forward HTML stuff */
01090          if (single && (f->frametype == AST_FRAME_HTML) && !ast_test_flag64(outgoing, DIAL_NOFORWARDHTML))
01091             if (ast_channel_sendhtml(outgoing->chan, f->subclass, f->data.ptr, f->datalen) == -1)
01092                ast_log(LOG_WARNING, "Unable to send URL\n");
01093 
01094          if (single && ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_DTMF_BEGIN) || (f->frametype == AST_FRAME_DTMF_END)))  {
01095             if (ast_write(outgoing->chan, f))
01096                ast_log(LOG_WARNING, "Unable to forward voice or dtmf\n");
01097          }
01098          if (single && (f->frametype == AST_FRAME_CONTROL) &&
01099             ((f->subclass == AST_CONTROL_HOLD) ||
01100             (f->subclass == AST_CONTROL_UNHOLD) ||
01101             (f->subclass == AST_CONTROL_VIDUPDATE) ||
01102              (f->subclass == AST_CONTROL_SRCUPDATE))) {
01103             ast_verb(3, "%s requested special control %d, passing it to %s\n", in->name, f->subclass, outgoing->chan->name);
01104             ast_indicate_data(outgoing->chan, f->subclass, f->data.ptr, f->datalen);
01105          }
01106          ast_frfree(f);
01107       }
01108       if (!*to)
01109          ast_verb(3, "Nobody picked up in %d ms\n", orig);
01110       if (!*to || ast_check_hangup(in))
01111          ast_cdr_noanswer(in->cdr);
01112    }
01113 
01114 #ifdef HAVE_EPOLL
01115    for (epollo = outgoing; epollo; epollo = epollo->next) {
01116       if (epollo->chan)
01117          ast_poll_channel_del(in, epollo->chan);
01118    }
01119 #endif
01120 
01121    return peer;
01122 }


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 = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, } [static]

Definition at line 2486 of file app_dial.c.

char* app = "Dial" [static]

Definition at line 463 of file app_dial.c.

Definition at line 2486 of file app_dial.c.

struct ast_app_option dial_exec_options[128] = { [ 'A' ] = { .flag = OPT_ANNOUNCE , .arg_index = OPT_ARG_ANNOUNCE + 1 }, [ 'C' ] = { .flag = OPT_RESETCDR }, [ 'c' ] = { .flag = ((uint64_t)1 << 33) }, [ 'd' ] = { .flag = OPT_DTMF_EXIT }, [ 'D' ] = { .flag = OPT_SENDDTMF , .arg_index = OPT_ARG_SENDDTMF + 1 }, [ 'e' ] = { .flag = ((uint64_t)1 << 34) }, [ 'f' ] = { .flag = OPT_FORCECLID }, [ 'F' ] = { .flag = ((uint64_t)1 << 35) , .arg_index = OPT_ARG_CALLEE_GO_ON + 1 }, [ 'g' ] = { .flag = OPT_GO_ON }, [ 'G' ] = { .flag = OPT_GOTO , .arg_index = OPT_ARG_GOTO + 1 }, [ 'h' ] = { .flag = OPT_CALLEE_HANGUP }, [ 'H' ] = { .flag = OPT_CALLER_HANGUP }, [ 'i' ] = { .flag = OPT_IGNORE_FORWARDING }, [ 'k' ] = { .flag = OPT_CALLEE_PARK }, [ 'K' ] = { .flag = OPT_CALLER_PARK }, [ 'L' ] = { .flag = OPT_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, [ 'm' ] = { .flag = OPT_MUSICBACK , .arg_index = OPT_ARG_MUSICBACK + 1 }, [ 'M' ] = { .flag = OPT_CALLEE_MACRO , .arg_index = OPT_ARG_CALLEE_MACRO + 1 }, [ 'n' ] = { .flag = OPT_SCREEN_NOINTRO , .arg_index = OPT_ARG_SCREEN_NOINTRO + 1 }, [ 'N' ] = { .flag = OPT_SCREEN_NOCLID }, [ 'o' ] = { .flag = OPT_ORIGINAL_CLID }, [ 'O' ] = { .flag = OPT_OPERMODE , .arg_index = OPT_ARG_OPERMODE + 1 }, [ 'p' ] = { .flag = OPT_SCREENING }, [ 'P' ] = { .flag = OPT_PRIVACY , .arg_index = OPT_ARG_PRIVACY + 1 }, [ 'r' ] = { .flag = OPT_RINGBACK }, [ 'S' ] = { .flag = OPT_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 't' ] = { .flag = OPT_CALLEE_TRANSFER }, [ 'T' ] = { .flag = OPT_CALLER_TRANSFER }, [ 'U' ] = { .flag = OPT_CALLEE_GOSUB , .arg_index = OPT_ARG_CALLEE_GOSUB + 1 }, [ 'w' ] = { .flag = OPT_CALLEE_MONITOR }, [ 'W' ] = { .flag = OPT_CALLER_MONITOR }, [ 'x' ] = { .flag = OPT_CALLEE_MIXMONITOR }, [ 'X' ] = { .flag = OPT_CALLER_MIXMONITOR }, } [static]

Definition at line 556 of file app_dial.c.

Referenced by dial_exec_full().

char* rapp = "RetryDial" [static]

Definition at line 464 of file app_dial.c.


Generated by  doxygen 1.6.2