Wed Aug 18 22:33:58 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"

Go to the source code of this file.

Data Structures

struct  cause_args
struct  chanlist
 List of channel drivers. More...
struct  privacy_args

Defines

#define AST_MAX_WATCHERS   256
#define CAN_EARLY_BRIDGE(flags, chan, peer)
#define DIAL_NOFORWARDHTML   ((uint64_t)1 << 32)
#define DIAL_STILLGOING   (1 << 31)
#define OPT_CALLEE_GO_ON   ((uint64_t)1 << 35)
#define OPT_CANCEL_ELSEWHERE   ((uint64_t)1 << 33)
#define OPT_PEER_H   ((uint64_t)1 << 34)
#define S_REPLACE(s, new_val)

Enumerations

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

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int detect_disconnect (struct ast_channel *chan, char code, struct ast_str *featurecode)
static int dial_exec (struct ast_channel *chan, void *data)
static int dial_exec_full (struct ast_channel *chan, void *data, struct ast_flags64 *peerflags, int *continue_exec)
static void do_forward (struct chanlist *o, struct cause_args *num, struct ast_flags64 *peerflags, int single)
static int do_timelimit (struct ast_channel *chan, struct ast_bridge_config *config, char *parse, struct timeval *calldurationlimit)
static void end_bridge_callback (void *data)
static void end_bridge_callback_data_fixup (struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
static const char * get_cid_name (char *name, int namelen, struct ast_channel *chan)
static void handle_cause (int cause, struct cause_args *num)
static void hanguptree (struct chanlist *outgoing, struct ast_channel *exception, int answered_elsewhere)
static int load_module (void)
static int onedigit_goto (struct ast_channel *chan, const char *context, char exten, int pri)
static void replace_macro_delimiter (char *s)
static int retrydial_exec (struct ast_channel *chan, void *data)
static void senddialendevent (const struct ast_channel *src, const char *dialstatus)
static void senddialevent (struct ast_channel *src, struct ast_channel *dst, const char *dialstring)
static int setup_privacy_args (struct privacy_args *pa, struct ast_flags64 *opts, char *opt_args[], struct ast_channel *chan)
 returns 1 if successful, 0 or <0 if the caller should 'goto out'
static int unload_module (void)
static int valid_priv_reply (struct ast_flags64 *opts, int res)
static struct ast_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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, }
static char * app = "Dial"
static struct ast_module_infoast_module_info = &__mod_info
static char * descrip
static struct ast_app_option dial_exec_options [128] = { [ 'A' ] = { .flag = OPT_ANNOUNCE , .arg_index = OPT_ARG_ANNOUNCE + 1 }, [ 'C' ] = { .flag = OPT_RESETCDR }, [ 'c' ] = { .flag = ((uint64_t)1 << 33) }, [ 'd' ] = { .flag = OPT_DTMF_EXIT }, [ 'D' ] = { .flag = OPT_SENDDTMF , .arg_index = OPT_ARG_SENDDTMF + 1 }, [ 'e' ] = { .flag = ((uint64_t)1 << 34) }, [ 'f' ] = { .flag = OPT_FORCECLID }, [ 'F' ] = { .flag = ((uint64_t)1 << 35) , .arg_index = OPT_ARG_CALLEE_GO_ON + 1 }, [ 'g' ] = { .flag = OPT_GO_ON }, [ 'G' ] = { .flag = OPT_GOTO , .arg_index = OPT_ARG_GOTO + 1 }, [ 'h' ] = { .flag = OPT_CALLEE_HANGUP }, [ 'H' ] = { .flag = OPT_CALLER_HANGUP }, [ 'i' ] = { .flag = OPT_IGNORE_FORWARDING }, [ 'k' ] = { .flag = OPT_CALLEE_PARK }, [ 'K' ] = { .flag = OPT_CALLER_PARK }, [ 'L' ] = { .flag = OPT_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, [ 'm' ] = { .flag = OPT_MUSICBACK , .arg_index = OPT_ARG_MUSICBACK + 1 }, [ 'M' ] = { .flag = OPT_CALLEE_MACRO , .arg_index = OPT_ARG_CALLEE_MACRO + 1 }, [ 'n' ] = { .flag = OPT_SCREEN_NOINTRO , .arg_index = OPT_ARG_SCREEN_NOINTRO + 1 }, [ 'N' ] = { .flag = OPT_SCREEN_NOCLID }, [ 'o' ] = { .flag = OPT_ORIGINAL_CLID }, [ 'O' ] = { .flag = OPT_OPERMODE , .arg_index = OPT_ARG_OPERMODE + 1 }, [ 'p' ] = { .flag = OPT_SCREENING }, [ 'P' ] = { .flag = OPT_PRIVACY , .arg_index = OPT_ARG_PRIVACY + 1 }, [ 'r' ] = { .flag = OPT_RINGBACK }, [ 'S' ] = { .flag = OPT_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 't' ] = { .flag = OPT_CALLEE_TRANSFER }, [ 'T' ] = { .flag = OPT_CALLER_TRANSFER }, [ 'U' ] = { .flag = OPT_CALLEE_GOSUB , .arg_index = OPT_ARG_CALLEE_GOSUB + 1 }, [ 'w' ] = { .flag = OPT_CALLEE_MONITOR }, [ 'W' ] = { .flag = OPT_CALLER_MONITOR }, [ 'x' ] = { .flag = OPT_CALLEE_MIXMONITOR }, [ 'X' ] = { .flag = OPT_CALLER_MIXMONITOR }, }
static char * rapp = "RetryDial"
static char * rdescrip
static char * rsynopsis = "Place a call, retrying on failure allowing optional exit extension."
static char * synopsis = "Place a call and connect to the current channel"


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

#define CAN_EARLY_BRIDGE ( flags,
chan,
peer   ) 

Value:

Definition at line 347 of file app_dial.c.

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

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

Definition at line 289 of file app_dial.c.

Referenced by dial_exec_full(), and wait_for_answer().

#define DIAL_STILLGOING   (1 << 31)

Definition at line 288 of file app_dial.c.

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

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

Definition at line 292 of file app_dial.c.

Referenced by dial_exec_full().

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

Definition at line 290 of file app_dial.c.

Referenced by dial_exec_full().

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

Definition at line 291 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 432 of file app_dial.c.


Enumeration Type Documentation

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

00255      {
00256    OPT_ANNOUNCE =          (1 << 0),
00257    OPT_RESETCDR =          (1 << 1),
00258    OPT_DTMF_EXIT =         (1 << 2),
00259    OPT_SENDDTMF =          (1 << 3),
00260    OPT_FORCECLID =         (1 << 4),
00261    OPT_GO_ON =             (1 << 5),
00262    OPT_CALLEE_HANGUP =     (1 << 6),
00263    OPT_CALLER_HANGUP =     (1 << 7),
00264    OPT_DURATION_LIMIT =    (1 << 9),
00265    OPT_MUSICBACK =         (1 << 10),
00266    OPT_CALLEE_MACRO =      (1 << 11),
00267    OPT_SCREEN_NOINTRO =    (1 << 12),
00268    OPT_SCREEN_NOCLID =     (1 << 13),
00269    OPT_ORIGINAL_CLID =     (1 << 14),
00270    OPT_SCREENING =         (1 << 15),
00271    OPT_PRIVACY =           (1 << 16),
00272    OPT_RINGBACK =          (1 << 17),
00273    OPT_DURATION_STOP =     (1 << 18),
00274    OPT_CALLEE_TRANSFER =   (1 << 19),
00275    OPT_CALLER_TRANSFER =   (1 << 20),
00276    OPT_CALLEE_MONITOR =    (1 << 21),
00277    OPT_CALLER_MONITOR =    (1 << 22),
00278    OPT_GOTO =              (1 << 23),
00279    OPT_OPERMODE =          (1 << 24),
00280    OPT_CALLEE_PARK =       (1 << 25),
00281    OPT_CALLER_PARK =       (1 << 26),
00282    OPT_IGNORE_FORWARDING = (1 << 27),
00283    OPT_CALLEE_GOSUB =      (1 << 28),
00284    OPT_CALLEE_MIXMONITOR = (1 << 29),
00285    OPT_CALLER_MIXMONITOR = (1 << 30),
00286 };

anonymous enum

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

00294      {
00295    OPT_ARG_ANNOUNCE = 0,
00296    OPT_ARG_SENDDTMF,
00297    OPT_ARG_GOTO,
00298    OPT_ARG_DURATION_LIMIT,
00299    OPT_ARG_MUSICBACK,
00300    OPT_ARG_CALLEE_MACRO,
00301    OPT_ARG_CALLEE_GOSUB,
00302    OPT_ARG_CALLEE_GO_ON,
00303    OPT_ARG_PRIVACY,
00304    OPT_ARG_DURATION_STOP,
00305    OPT_ARG_OPERMODE,
00306    OPT_ARG_SCREEN_NOINTRO,
00307    /* note: this entry _MUST_ be the last one in the enum */
00308    OPT_ARG_ARRAY_SIZE,
00309 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 2286 of file app_dial.c.

static void __unreg_module ( void   )  [static]

Definition at line 2286 of file app_dial.c.

static int detect_disconnect ( struct ast_channel chan,
char  code,
struct ast_str featurecode 
) [static]

Definition at line 910 of file app_dial.c.

References ast_feature_detect(), AST_FEATURE_DISCONNECT, AST_FEATURE_RETURN_STOREDIGITS, ast_str_append(), ast_str_buffer, ast_str_reset(), chan, and ast_call_feature::feature_mask.

00911 {
00912    struct ast_flags features = { AST_FEATURE_DISCONNECT }; /* only concerned with disconnect feature */
00913    struct ast_call_feature feature = { 0, };
00914    int res;
00915 
00916    ast_str_append(&featurecode, 1, "%c", code);
00917 
00918    res = ast_feature_detect(chan, &features, ast_str_buffer(featurecode), &feature);
00919 
00920    if (res != AST_FEATURE_RETURN_STOREDIGITS) {
00921       ast_str_reset(featurecode);
00922    }
00923    if (feature.feature_mask & AST_FEATURE_DISCONNECT) {
00924       return 1;
00925    }
00926 
00927    return 0;
00928 }

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

Definition at line 2136 of file app_dial.c.

References chan, and dial_exec_full().

Referenced by load_module().

02137 {
02138    struct ast_flags64 peerflags;
02139 
02140    memset(&peerflags, 0, sizeof(peerflags));
02141 
02142    return dial_exec_full(chan, data, &peerflags, NULL);
02143 }

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

Definition at line 1321 of file app_dial.c.

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

Referenced by dial_exec(), and retrydial_exec().

01322 {
01323    int res = -1; /* default: error */
01324    char *rest, *cur; /* scan the list of destinations */
01325    struct chanlist *outgoing = NULL; /* list of destinations */
01326    struct ast_channel *peer;
01327    int to; /* timeout */
01328    struct cause_args num = { chan, 0, 0, 0 };
01329    int cause;
01330    char numsubst[256];
01331    char cidname[AST_MAX_EXTENSION] = "";
01332 
01333    struct ast_bridge_config config = { { 0, } };
01334    struct timeval calldurationlimit = { 0, };
01335    char *dtmfcalled = NULL, *dtmfcalling = NULL;
01336    struct privacy_args pa = {
01337       .sentringing = 0,
01338       .privdb_val = 0,
01339       .status = "INVALIDARGS",
01340    };
01341    int sentringing = 0, moh = 0;
01342    const char *outbound_group = NULL;
01343    int result = 0;
01344    char *parse;
01345    int opermode = 0;
01346    int delprivintro = 0;
01347    AST_DECLARE_APP_ARGS(args,
01348       AST_APP_ARG(peers);
01349       AST_APP_ARG(timeout);
01350       AST_APP_ARG(options);
01351       AST_APP_ARG(url);
01352    );
01353    struct ast_flags64 opts = { 0, };
01354    char *opt_args[OPT_ARG_ARRAY_SIZE];
01355    struct ast_datastore *datastore = NULL;
01356    int fulldial = 0, num_dialed = 0;
01357 
01358    /* Reset all DIAL variables back to blank, to prevent confusion (in case we don't reset all of them). */
01359    pbx_builtin_setvar_helper(chan, "DIALSTATUS", "");
01360    pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", "");
01361    pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", "");
01362    pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", "");
01363    pbx_builtin_setvar_helper(chan, "DIALEDTIME", "");
01364 
01365    if (ast_strlen_zero(data)) {
01366       ast_log(LOG_WARNING, "Dial requires an argument (technology/number)\n");
01367       pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
01368       return -1;
01369    }
01370 
01371    parse = ast_strdupa(data);
01372 
01373    AST_STANDARD_APP_ARGS(args, parse);
01374 
01375    if (!ast_strlen_zero(args.options) &&
01376       ast_app_parse_options64(dial_exec_options, &opts, opt_args, args.options)) {
01377       pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
01378       goto done;
01379    }
01380 
01381    if (ast_strlen_zero(args.peers)) {
01382       ast_log(LOG_WARNING, "Dial requires an argument (technology/number)\n");
01383       pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
01384       goto done;
01385    }
01386 
01387    if (ast_test_flag64(&opts, OPT_SCREEN_NOINTRO) && !ast_strlen_zero(opt_args[OPT_ARG_SCREEN_NOINTRO])) {
01388       delprivintro = atoi(opt_args[OPT_ARG_SCREEN_NOINTRO]);
01389       if (delprivintro < 0 || delprivintro > 1) {
01390          ast_log(LOG_WARNING, "Unknown argument %d to n option, ignoring\n", delprivintro);
01391          delprivintro = 0;
01392       }
01393    }
01394 
01395    if (ast_test_flag64(&opts, OPT_OPERMODE)) {
01396       opermode = ast_strlen_zero(opt_args[OPT_ARG_OPERMODE]) ? 1 : atoi(opt_args[OPT_ARG_OPERMODE]);
01397       ast_verb(3, "Setting operator services mode to %d.\n", opermode);
01398    }
01399    
01400    if (ast_test_flag64(&opts, OPT_DURATION_STOP) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_STOP])) {
01401       calldurationlimit.tv_sec = atoi(opt_args[OPT_ARG_DURATION_STOP]);
01402       if (!calldurationlimit.tv_sec) {
01403          ast_log(LOG_WARNING, "Dial does not accept S(%s), hanging up.\n", opt_args[OPT_ARG_DURATION_STOP]);
01404          pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
01405          goto done;
01406       }
01407       ast_verb(3, "Setting call duration limit to %.3lf seconds.\n", calldurationlimit.tv_sec + calldurationlimit.tv_usec / 1000000.0);
01408    }
01409 
01410    if (ast_test_flag64(&opts, OPT_SENDDTMF) && !ast_strlen_zero(opt_args[OPT_ARG_SENDDTMF])) {
01411       dtmfcalling = opt_args[OPT_ARG_SENDDTMF];
01412       dtmfcalled = strsep(&dtmfcalling, ":");
01413    }
01414 
01415    if (ast_test_flag64(&opts, OPT_DURATION_LIMIT) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])) {
01416       if (do_timelimit(chan, &config, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit))
01417          goto done;
01418    }
01419 
01420    if (ast_test_flag64(&opts, OPT_RESETCDR) && chan->cdr)
01421       ast_cdr_reset(chan->cdr, NULL);
01422    if (ast_test_flag64(&opts, OPT_PRIVACY) && ast_strlen_zero(opt_args[OPT_ARG_PRIVACY]))
01423       opt_args[OPT_ARG_PRIVACY] = ast_strdupa(chan->exten);
01424 
01425    if (ast_test_flag64(&opts, OPT_PRIVACY) || ast_test_flag64(&opts, OPT_SCREENING)) {
01426       res = setup_privacy_args(&pa, &opts, opt_args, chan);
01427       if (res <= 0)
01428          goto out;
01429       res = -1; /* reset default */
01430    }
01431 
01432    if (ast_test_flag64(&opts, OPT_DTMF_EXIT) || ast_test_flag64(&opts, OPT_CALLER_HANGUP)) {
01433       __ast_answer(chan, 0, 0);
01434    }
01435 
01436    if (continue_exec)
01437       *continue_exec = 0;
01438 
01439    /* If a channel group has been specified, get it for use when we create peer channels */
01440 
01441    ast_channel_lock(chan);
01442    if ((outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP_ONCE"))) {
01443       outbound_group = ast_strdupa(outbound_group);   
01444       pbx_builtin_setvar_helper(chan, "OUTBOUND_GROUP_ONCE", NULL);
01445    } else if ((outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP"))) {
01446       outbound_group = ast_strdupa(outbound_group);
01447    }
01448    ast_channel_unlock(chan);  
01449    ast_copy_flags64(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING | OPT_ANNOUNCE | OPT_CALLEE_MACRO | OPT_CALLEE_GOSUB);
01450 
01451    /* loop through the list of dial destinations */
01452    rest = args.peers;
01453    while ((cur = strsep(&rest, "&")) ) {
01454       struct chanlist *tmp;
01455       struct ast_channel *tc; /* channel for this destination */
01456       /* Get a technology/[device:]number pair */
01457       char *number = cur;
01458       char *interface = ast_strdupa(number);
01459       char *tech = strsep(&number, "/");
01460       /* find if we already dialed this interface */
01461       struct ast_dialed_interface *di;
01462       AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces;
01463       num_dialed++;
01464       if (!number) {
01465          ast_log(LOG_WARNING, "Dial argument takes format (technology/[device:]number1)\n");
01466          goto out;
01467       }
01468       if (!(tmp = ast_calloc(1, sizeof(*tmp))))
01469          goto out;
01470       if (opts.flags) {
01471          ast_copy_flags64(tmp, &opts,
01472             OPT_CANCEL_ELSEWHERE |
01473             OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
01474             OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
01475             OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
01476             OPT_CALLEE_PARK | OPT_CALLER_PARK |
01477             OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR |
01478             OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID);
01479          ast_set2_flag64(tmp, args.url, DIAL_NOFORWARDHTML);
01480       }
01481       ast_copy_string(numsubst, number, sizeof(numsubst));
01482       /* Request the peer */
01483 
01484       ast_channel_lock(chan);
01485       datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL);
01486       ast_channel_unlock(chan);
01487 
01488       if (datastore)
01489          dialed_interfaces = datastore->data;
01490       else {
01491          if (!(datastore = ast_datastore_alloc(&dialed_interface_info, NULL))) {
01492             ast_log(LOG_WARNING, "Unable to create channel datastore for dialed interfaces. Aborting!\n");
01493             ast_free(tmp);
01494             goto out;
01495          }
01496 
01497          datastore->inheritance = DATASTORE_INHERIT_FOREVER;
01498 
01499          if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) {
01500             ast_datastore_free(datastore);
01501             ast_free(tmp);
01502             goto out;
01503          }
01504 
01505          datastore->data = dialed_interfaces;
01506          AST_LIST_HEAD_INIT(dialed_interfaces);
01507 
01508          ast_channel_lock(chan);
01509          ast_channel_datastore_add(chan, datastore);
01510          ast_channel_unlock(chan);
01511       }
01512 
01513       AST_LIST_LOCK(dialed_interfaces);
01514       AST_LIST_TRAVERSE(dialed_interfaces, di, list) {
01515          if (!strcasecmp(di->interface, interface)) {
01516             ast_log(LOG_WARNING, "Skipping dialing interface '%s' again since it has already been dialed\n",
01517                di->interface);
01518             break;
01519          }
01520       }
01521       AST_LIST_UNLOCK(dialed_interfaces);
01522 
01523       if (di) {
01524          fulldial++;
01525          ast_free(tmp);
01526          continue;
01527       }
01528 
01529       /* It is always ok to dial a Local interface.  We only keep track of
01530        * which "real" interfaces have been dialed.  The Local channel will
01531        * inherit this list so that if it ends up dialing a real interface,
01532        * it won't call one that has already been called. */
01533       if (strcasecmp(tech, "Local")) {
01534          if (!(di = ast_calloc(1, sizeof(*di) + strlen(interface)))) {
01535             AST_LIST_UNLOCK(dialed_interfaces);
01536             ast_free(tmp);
01537             goto out;
01538          }
01539          strcpy(di->interface, interface);
01540 
01541          AST_LIST_LOCK(dialed_interfaces);
01542          AST_LIST_INSERT_TAIL(dialed_interfaces, di, list);
01543          AST_LIST_UNLOCK(dialed_interfaces);
01544       }
01545 
01546       tc = ast_request(tech, chan->nativeformats, numsubst, &cause);
01547       if (!tc) {
01548          /* If we can't, just go on to the next call */
01549          ast_log(LOG_WARNING, "Unable to create channel of type '%s' (cause %d - %s)\n",
01550             tech, cause, ast_cause2str(cause));
01551          handle_cause(cause, &num);
01552          if (!rest) /* we are on the last destination */
01553             chan->hangupcause = cause;
01554          ast_free(tmp);
01555          continue;
01556       }
01557       pbx_builtin_setvar_helper(tc, "DIALEDPEERNUMBER", numsubst);
01558 
01559       /* Setup outgoing SDP to match incoming one */
01560       if (CAN_EARLY_BRIDGE(peerflags, chan, tc)) {
01561          ast_rtp_make_compatible(tc, chan, !outgoing && !rest);
01562       }
01563       
01564       /* Inherit specially named variables from parent channel */
01565       ast_channel_inherit_variables(chan, tc);
01566       ast_channel_datastore_inherit(chan, tc);
01567 
01568       tc->appl = "AppDial";
01569       tc->data = "(Outgoing Line)";
01570       memset(&tc->whentohangup, 0, sizeof(tc->whentohangup));
01571 
01572       S_REPLACE(tc->cid.cid_num, ast_strdup(chan->cid.cid_num));
01573       S_REPLACE(tc->cid.cid_name, ast_strdup(chan->cid.cid_name));
01574       S_REPLACE(tc->cid.cid_ani, ast_strdup(chan->cid.cid_ani));
01575       S_REPLACE(tc->cid.cid_rdnis, ast_strdup(chan->cid.cid_rdnis));
01576       
01577       ast_string_field_set(tc, accountcode, chan->accountcode);
01578       tc->cdrflags = chan->cdrflags;
01579       if (ast_strlen_zero(tc->musicclass))
01580          ast_string_field_set(tc, musicclass, chan->musicclass);
01581       /* Pass callingpres, type of number, tns, ADSI CPE, transfer capability */
01582       tc->cid.cid_pres = chan->cid.cid_pres;
01583       tc->cid.cid_ton = chan->cid.cid_ton;
01584       tc->cid.cid_tns = chan->cid.cid_tns;
01585       tc->cid.cid_ani2 = chan->cid.cid_ani2;
01586       tc->adsicpe = chan->adsicpe;
01587       tc->transfercapability = chan->transfercapability;
01588 
01589       /* If we have an outbound group, set this peer channel to it */
01590       if (outbound_group)
01591          ast_app_group_set_channel(tc, outbound_group);
01592 
01593       /* Inherit context and extension */
01594       ast_string_field_set(tc, dialcontext, ast_strlen_zero(chan->macrocontext) ? chan->context : chan->macrocontext);
01595       if (!ast_strlen_zero(chan->macroexten))
01596          ast_copy_string(tc->exten, chan->macroexten, sizeof(tc->exten));
01597       else
01598          ast_copy_string(tc->exten, chan->exten, sizeof(tc->exten));
01599 
01600       res = ast_call(tc, numsubst, 0); /* Place the call, but don't wait on the answer */
01601 
01602       /* Save the info in cdr's that we called them */
01603       if (chan->cdr)
01604          ast_cdr_setdestchan(chan->cdr, tc->name);
01605 
01606       /* check the results of ast_call */
01607       if (res) {
01608          /* Again, keep going even if there's an error */
01609          ast_debug(1, "ast call on peer returned %d\n", res);
01610          ast_verb(3, "Couldn't call %s\n", numsubst);
01611          if (tc->hangupcause) {
01612             chan->hangupcause = tc->hangupcause;
01613          }
01614          ast_hangup(tc);
01615          tc = NULL;
01616          ast_free(tmp);
01617          continue;
01618       } else {
01619          senddialevent(chan, tc, numsubst);
01620          ast_verb(3, "Called %s\n", numsubst);
01621          if (!ast_test_flag64(peerflags, OPT_ORIGINAL_CLID))
01622             ast_set_callerid(tc, S_OR(chan->macroexten, chan->exten), get_cid_name(cidname, sizeof(cidname), chan), NULL);
01623       }
01624       /* Put them in the list of outgoing thingies...  We're ready now.
01625          XXX If we're forcibly removed, these outgoing calls won't get
01626          hung up XXX */
01627       ast_set_flag64(tmp, DIAL_STILLGOING);
01628       tmp->chan = tc;
01629       tmp->next = outgoing;
01630       outgoing = tmp;
01631       /* If this line is up, don't try anybody else */
01632       if (outgoing->chan->_state == AST_STATE_UP)
01633          break;
01634    }
01635    
01636    if (ast_strlen_zero(args.timeout)) {
01637       to = -1;
01638    } else {
01639       to = atoi(args.timeout);
01640       if (to > 0)
01641          to *= 1000;
01642       else {
01643          ast_log(LOG_WARNING, "Invalid timeout specified: '%s'. Setting timeout to infinite\n", args.timeout);
01644          to = -1;
01645       }
01646    }
01647 
01648    if (!outgoing) {
01649       strcpy(pa.status, "CHANUNAVAIL");
01650       if (fulldial == num_dialed) {
01651          res = -1;
01652          goto out;
01653       }
01654    } else {
01655       /* Our status will at least be NOANSWER */
01656       strcpy(pa.status, "NOANSWER");
01657       if (ast_test_flag64(outgoing, OPT_MUSICBACK)) {
01658          moh = 1;
01659          if (!ast_strlen_zero(opt_args[OPT_ARG_MUSICBACK])) {
01660             char *original_moh = ast_strdupa(chan->musicclass);
01661             ast_string_field_set(chan, musicclass, opt_args[OPT_ARG_MUSICBACK]);
01662             ast_moh_start(chan, opt_args[OPT_ARG_MUSICBACK], NULL);
01663             ast_string_field_set(chan, musicclass, original_moh);
01664          } else {
01665             ast_moh_start(chan, NULL, NULL);
01666          }
01667          ast_indicate(chan, AST_CONTROL_PROGRESS);
01668       } else if (ast_test_flag64(outgoing, OPT_RINGBACK)) {
01669          ast_indicate(chan, AST_CONTROL_RINGING);
01670          sentringing++;
01671       }
01672    }
01673 
01674    peer = wait_for_answer(chan, outgoing, &to, peerflags, &pa, &num, &result);
01675 
01676    /* The ast_channel_datastore_remove() function could fail here if the
01677     * datastore was moved to another channel during a masquerade. If this is
01678     * the case, don't free the datastore here because later, when the channel
01679     * to which the datastore was moved hangs up, it will attempt to free this
01680     * datastore again, causing a crash
01681     */
01682    if (!ast_channel_datastore_remove(chan, datastore))
01683       ast_datastore_free(datastore);
01684    if (!peer) {
01685       if (result) {
01686          res = result;
01687       } else if (to) { /* Musta gotten hung up */
01688          res = -1;
01689       } else { /* Nobody answered, next please? */
01690          res = 0;
01691       }
01692 
01693       /* SIP, in particular, sends back this error code to indicate an
01694        * overlap dialled number needs more digits. */
01695       if (chan->hangupcause == AST_CAUSE_INVALID_NUMBER_FORMAT) {
01696          res = AST_PBX_INCOMPLETE;
01697       }
01698 
01699       /* almost done, although the 'else' block is 400 lines */
01700    } else {
01701       const char *number;
01702 
01703       strcpy(pa.status, "ANSWER");
01704       pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
01705       /* Ah ha!  Someone answered within the desired timeframe.  Of course after this
01706          we will always return with -1 so that it is hung up properly after the
01707          conversation.  */
01708       hanguptree(outgoing, peer, 1);
01709       outgoing = NULL;
01710       /* If appropriate, log that we have a destination channel */
01711       if (chan->cdr)
01712          ast_cdr_setdestchan(chan->cdr, peer->name);
01713       if (peer->name)
01714          pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", peer->name);
01715       
01716       ast_channel_lock(peer);
01717       number = pbx_builtin_getvar_helper(peer, "DIALEDPEERNUMBER"); 
01718       if (!number)
01719          number = numsubst;
01720       pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", number);
01721       ast_channel_unlock(peer);
01722 
01723       if (!ast_strlen_zero(args.url) && ast_channel_supports_html(peer) ) {
01724          ast_debug(1, "app_dial: sendurl=%s.\n", args.url);
01725          ast_channel_sendurl( peer, args.url );
01726       }
01727       if ( (ast_test_flag64(&opts, OPT_PRIVACY) || ast_test_flag64(&opts, OPT_SCREENING)) && pa.privdb_val == AST_PRIVACY_UNKNOWN) {
01728          if (do_privacy(chan, peer, &opts, opt_args, &pa)) {
01729             res = 0;
01730             goto out;
01731          }
01732       }
01733       if (!ast_test_flag64(&opts, OPT_ANNOUNCE) || ast_strlen_zero(opt_args[OPT_ARG_ANNOUNCE])) {
01734          res = 0;
01735       } else {
01736          int digit = 0;
01737          struct ast_channel *chans[2];
01738          struct ast_channel *active_chan;
01739 
01740          chans[0] = chan;
01741          chans[1] = peer;
01742 
01743          /* we need to stream the announcment while monitoring the caller for a hangup */
01744 
01745          /* stream the file */
01746          res = ast_streamfile(peer, opt_args[OPT_ARG_ANNOUNCE], peer->language);
01747          if (res) {
01748             res = 0;
01749             ast_log(LOG_ERROR, "error streaming file '%s' to callee\n", opt_args[OPT_ARG_ANNOUNCE]);
01750          }
01751 
01752          ast_set_flag(peer, AST_FLAG_END_DTMF_ONLY);
01753          while (peer->stream) {
01754             int ms;
01755 
01756             ms = ast_sched_wait(peer->sched);
01757 
01758             if (ms < 0 && !peer->timingfunc) {
01759                ast_stopstream(peer);
01760                break;
01761             }
01762             if (ms < 0)
01763                ms = 1000;
01764 
01765             active_chan = ast_waitfor_n(chans, 2, &ms);
01766             if (active_chan) {
01767                struct ast_frame *fr = ast_read(active_chan);
01768                if (!fr) {
01769                   ast_hangup(peer);
01770                   res = -1;
01771                   goto done;
01772                }
01773                switch(fr->frametype) {
01774                   case AST_FRAME_DTMF_END:
01775                      digit = fr->subclass;
01776                      if (active_chan == peer && strchr(AST_DIGIT_ANY, res)) {
01777                         ast_stopstream(peer);
01778                         res = ast_senddigit(chan, digit, 0);
01779                      }
01780                      break;
01781                   case AST_FRAME_CONTROL:
01782                      switch (fr->subclass) {
01783                         case AST_CONTROL_HANGUP:
01784                            ast_frfree(fr);
01785                            ast_hangup(peer);
01786                            res = -1;
01787                            goto done;
01788                         default:
01789                            break;
01790                      }
01791                      break;
01792                   default:
01793                      /* Ignore all others */
01794                      break;
01795                }
01796                ast_frfree(fr);
01797             }
01798             ast_sched_runq(peer->sched);
01799          }
01800          ast_clear_flag(peer, AST_FLAG_END_DTMF_ONLY);
01801       }
01802 
01803       if (chan && peer && ast_test_flag64(&opts, OPT_GOTO) && !ast_strlen_zero(opt_args[OPT_ARG_GOTO])) {
01804          replace_macro_delimiter(opt_args[OPT_ARG_GOTO]);
01805          ast_parseable_goto(chan, opt_args[OPT_ARG_GOTO]);
01806          /* peer goes to the same context and extension as chan, so just copy info from chan*/
01807          ast_copy_string(peer->context, chan->context, sizeof(peer->context));
01808          ast_copy_string(peer->exten, chan->exten, sizeof(peer->exten));
01809          peer->priority = chan->priority + 2;
01810          ast_pbx_start(peer);
01811          hanguptree(outgoing, NULL, ast_test_flag64(&opts, OPT_CANCEL_ELSEWHERE) ? 1 : 0);
01812          if (continue_exec)
01813             *continue_exec = 1;
01814          res = 0;
01815          goto done;
01816       }
01817 
01818       if (ast_test_flag64(&opts, OPT_CALLEE_MACRO) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_MACRO])) {
01819          struct ast_app *theapp;
01820          const char *macro_result;
01821 
01822          res = ast_autoservice_start(chan);
01823          if (res) {
01824             ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
01825             res = -1;
01826          }
01827 
01828          theapp = pbx_findapp("Macro");
01829 
01830          if (theapp && !res) { /* XXX why check res here ? */
01831             /* Set peer->exten and peer->context so that MACRO_EXTEN and MACRO_CONTEXT get set */
01832             ast_copy_string(peer->context, chan->context, sizeof(peer->context));
01833             ast_copy_string(peer->exten, chan->exten, sizeof(peer->exten));
01834 
01835             replace_macro_delimiter(opt_args[OPT_ARG_CALLEE_MACRO]);
01836             res = pbx_exec(peer, theapp, opt_args[OPT_ARG_CALLEE_MACRO]);
01837             ast_debug(1, "Macro exited with status %d\n", res);
01838             res = 0;
01839          } else {
01840             ast_log(LOG_ERROR, "Could not find application Macro\n");
01841             res = -1;
01842          }
01843 
01844          if (ast_autoservice_stop(chan) < 0) {
01845             res = -1;
01846          }
01847 
01848          ast_channel_lock(peer);
01849 
01850          if (!res && (macro_result = pbx_builtin_getvar_helper(peer, "MACRO_RESULT"))) {
01851             char *macro_transfer_dest;
01852 
01853             if (!strcasecmp(macro_result, "BUSY")) {
01854                ast_copy_string(pa.status, macro_result, sizeof(pa.status));
01855                ast_set_flag64(peerflags, OPT_GO_ON);
01856                res = -1;
01857             } else if (!strcasecmp(macro_result, "CONGESTION") || !strcasecmp(macro_result, "CHANUNAVAIL")) {
01858                ast_copy_string(pa.status, macro_result, sizeof(pa.status));
01859                ast_set_flag64(peerflags, OPT_GO_ON);
01860                res = -1;
01861             } else if (!strcasecmp(macro_result, "CONTINUE")) {
01862                /* hangup peer and keep chan alive assuming the macro has changed
01863                   the context / exten / priority or perhaps
01864                   the next priority in the current exten is desired.
01865                */
01866                ast_set_flag64(peerflags, OPT_GO_ON);
01867                res = -1;
01868             } else if (!strcasecmp(macro_result, "ABORT")) {
01869                /* Hangup both ends unless the caller has the g flag */
01870                res = -1;
01871             } else if (!strncasecmp(macro_result, "GOTO:", 5) && (macro_transfer_dest = ast_strdupa(macro_result + 5))) {
01872                res = -1;
01873                /* perform a transfer to a new extension */
01874                if (strchr(macro_transfer_dest, '^')) { /* context^exten^priority*/
01875                   replace_macro_delimiter(macro_transfer_dest);
01876                   if (!ast_parseable_goto(chan, macro_transfer_dest))
01877                      ast_set_flag64(peerflags, OPT_GO_ON);
01878                }
01879             }
01880          }
01881 
01882          ast_channel_unlock(peer);
01883       }
01884 
01885       if (ast_test_flag64(&opts, OPT_CALLEE_GOSUB) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GOSUB])) {
01886          struct ast_app *theapp;
01887          const char *gosub_result;
01888          char *gosub_args, *gosub_argstart;
01889          int res9 = -1;
01890 
01891          res9 = ast_autoservice_start(chan);
01892          if (res9) {
01893             ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
01894             res9 = -1;
01895          }
01896 
01897          theapp = pbx_findapp("Gosub");
01898 
01899          if (theapp && !res9) {
01900             replace_macro_delimiter(opt_args[OPT_ARG_CALLEE_GOSUB]);
01901 
01902             /* Set where we came from */
01903             ast_copy_string(peer->context, "app_dial_gosub_virtual_context", sizeof(peer->context));
01904             ast_copy_string(peer->exten, "s", sizeof(peer->exten));
01905             peer->priority = 0;
01906 
01907             gosub_argstart = strchr(opt_args[OPT_ARG_CALLEE_GOSUB], ',');
01908             if (gosub_argstart) {
01909                *gosub_argstart = 0;
01910                if (asprintf(&gosub_args, "%s,s,1(%s)", opt_args[OPT_ARG_CALLEE_GOSUB], gosub_argstart + 1) < 0) {
01911                   ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
01912                   gosub_args = NULL;
01913                }
01914                *gosub_argstart = ',';
01915             } else {
01916                if (asprintf(&gosub_args, "%s,s,1", opt_args[OPT_ARG_CALLEE_GOSUB]) < 0) {
01917                   ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
01918                   gosub_args = NULL;
01919                }
01920             }
01921 
01922             if (gosub_args) {
01923                res9 = pbx_exec(peer, theapp, gosub_args);
01924                if (!res9) {
01925                   struct ast_pbx_args args;
01926                   /* A struct initializer fails to compile for this case ... */
01927                   memset(&args, 0, sizeof(args));
01928                   args.no_hangup_chan = 1;
01929                   ast_pbx_run_args(peer, &args);
01930                }
01931                ast_free(gosub_args);
01932                ast_debug(1, "Gosub exited with status %d\n", res9);
01933             } else {
01934                ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n");
01935             }
01936 
01937          } else if (!res9) {
01938             ast_log(LOG_ERROR, "Could not find application Gosub\n");
01939             res9 = -1;
01940          }
01941 
01942          if (ast_autoservice_stop(chan) < 0) {
01943             ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
01944             res9 = -1;
01945          }
01946          
01947          ast_channel_lock(peer);
01948 
01949          if (!res9 && (gosub_result = pbx_builtin_getvar_helper(peer, "GOSUB_RESULT"))) {
01950             char *gosub_transfer_dest;
01951 
01952             if (!strcasecmp(gosub_result, "BUSY")) {
01953                ast_copy_string(pa.status, gosub_result, sizeof(pa.status));
01954                ast_set_flag64(peerflags, OPT_GO_ON);
01955                res = -1;
01956             } else if (!strcasecmp(gosub_result, "CONGESTION") || !strcasecmp(gosub_result, "CHANUNAVAIL")) {
01957                ast_copy_string(pa.status, gosub_result, sizeof(pa.status));
01958                ast_set_flag64(peerflags, OPT_GO_ON);
01959                res = -1;
01960             } else if (!strcasecmp(gosub_result, "CONTINUE")) {
01961                /* hangup peer and keep chan alive assuming the macro has changed
01962                   the context / exten / priority or perhaps
01963                   the next priority in the current exten is desired.
01964                */
01965                ast_set_flag64(peerflags, OPT_GO_ON);
01966                res = -1;
01967             } else if (!strcasecmp(gosub_result, "ABORT")) {
01968                /* Hangup both ends unless the caller has the g flag */
01969                res = -1;
01970             } else if (!strncasecmp(gosub_result, "GOTO:", 5) && (gosub_transfer_dest = ast_strdupa(gosub_result + 5))) {
01971                res = -1;
01972                /* perform a transfer to a new extension */
01973                if (strchr(gosub_transfer_dest, '^')) { /* context^exten^priority*/
01974                   replace_macro_delimiter(gosub_transfer_dest);
01975                   if (!ast_parseable_goto(chan, gosub_transfer_dest))
01976                      ast_set_flag64(peerflags, OPT_GO_ON);
01977                }
01978             }
01979          }
01980 
01981          ast_channel_unlock(peer);  
01982       }
01983 
01984       if (!res) {
01985          if (!ast_tvzero(calldurationlimit)) {
01986             struct timeval whentohangup = calldurationlimit;
01987             peer->whentohangup = ast_tvadd(ast_tvnow(), whentohangup);
01988          }
01989          if (!ast_strlen_zero(dtmfcalled)) {
01990             ast_verb(3, "Sending DTMF '%s' to the called party.\n", dtmfcalled);
01991             res = ast_dtmf_stream(peer, chan, dtmfcalled, 250, 0);
01992          }
01993          if (!ast_strlen_zero(dtmfcalling)) {
01994             ast_verb(3, "Sending DTMF '%s' to the calling party.\n", dtmfcalling);
01995             res = ast_dtmf_stream(chan, peer, dtmfcalling, 250, 0);
01996          }
01997       }
01998 
01999       if (res) { /* some error */
02000          res = -1;
02001       } else {
02002          if (ast_test_flag64(peerflags, OPT_CALLEE_TRANSFER))
02003             ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
02004          if (ast_test_flag64(peerflags, OPT_CALLER_TRANSFER))
02005             ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
02006          if (ast_test_flag64(peerflags, OPT_CALLEE_HANGUP))
02007             ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
02008          if (ast_test_flag64(peerflags, OPT_CALLER_HANGUP))
02009             ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
02010          if (ast_test_flag64(peerflags, OPT_CALLEE_MONITOR))
02011             ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
02012          if (ast_test_flag64(peerflags, OPT_CALLER_MONITOR))
02013             ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
02014          if (ast_test_flag64(peerflags, OPT_CALLEE_PARK))
02015             ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
02016          if (ast_test_flag64(peerflags, OPT_CALLER_PARK))
02017             ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
02018          if (ast_test_flag64(peerflags, OPT_CALLEE_MIXMONITOR))
02019             ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMIXMON);
02020          if (ast_test_flag64(peerflags, OPT_CALLER_MIXMONITOR))
02021             ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMIXMON);
02022          if (ast_test_flag64(peerflags, OPT_GO_ON))
02023             ast_set_flag(&(config.features_caller), AST_FEATURE_NO_H_EXTEN);
02024 
02025          config.end_bridge_callback = end_bridge_callback;
02026          config.end_bridge_callback_data = chan;
02027          config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
02028          
02029          if (moh) {
02030             moh = 0;
02031             ast_moh_stop(chan);
02032          } else if (sentringing) {
02033             sentringing = 0;
02034             ast_indicate(chan, -1);
02035          }
02036          /* Be sure no generators are left on it */
02037          ast_deactivate_generator(chan);
02038          /* Make sure channels are compatible */
02039          res = ast_channel_make_compatible(chan, peer);
02040          if (res < 0) {
02041             ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", chan->name, peer->name);
02042             ast_hangup(peer);
02043             res = -1;
02044             goto done;
02045          }
02046          if (opermode && !strncmp(chan->tech->type, "DAHDI", 5) && !strncmp(peer->name, "DAHDI", 5)) {
02047             /* what's this special handling for dahdi <-> dahdi ?
02048              * A: dahdi to dahdi calls are natively bridged at the kernel driver
02049              * level, so we need to ensure that this mode gets propagated
02050              * all the way down. */
02051             struct oprmode oprmode;
02052 
02053             oprmode.peer = peer;
02054             oprmode.mode = opermode;
02055 
02056             ast_channel_setoption(chan, AST_OPTION_OPRMODE, &oprmode, sizeof(oprmode), 0);
02057          }
02058          res = ast_bridge_call(chan, peer, &config);
02059       }
02060 
02061       strcpy(peer->context, chan->context);
02062 
02063       if (ast_test_flag64(&opts, OPT_PEER_H) && ast_exists_extension(peer, peer->context, "h", 1, peer->cid.cid_num)) {
02064          int autoloopflag;
02065          int found;
02066          int res9;
02067          
02068          strcpy(peer->exten, "h");
02069          peer->priority = 1;
02070          autoloopflag = ast_test_flag(peer, AST_FLAG_IN_AUTOLOOP); /* save value to restore at the end */
02071          ast_set_flag(peer, AST_FLAG_IN_AUTOLOOP);
02072 
02073          while ((res9 = ast_spawn_extension(peer, peer->context, peer->exten, peer->priority, peer->cid.cid_num, &found, 1)) == 0)
02074             peer->priority++;
02075 
02076          if (found && res9) {
02077             /* Something bad happened, or a hangup has been requested. */
02078             ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", peer->context, peer->exten, peer->priority, peer->name);
02079             ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", peer->context, peer->exten, peer->priority, peer->name);
02080          }
02081          ast_set2_flag(peer, autoloopflag, AST_FLAG_IN_AUTOLOOP);  /* set it back the way it was */
02082       }
02083       if (!ast_check_hangup(peer) && ast_test_flag64(&opts, OPT_CALLEE_GO_ON) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GO_ON])) {      
02084          replace_macro_delimiter(opt_args[OPT_ARG_CALLEE_GO_ON]);
02085          ast_parseable_goto(peer, opt_args[OPT_ARG_CALLEE_GO_ON]);
02086          ast_pbx_start(peer);
02087       } else {
02088          if (!ast_check_hangup(chan))
02089             chan->hangupcause = peer->hangupcause;
02090          ast_hangup(peer);
02091       }
02092    }
02093 out:
02094    if (moh) {
02095       moh = 0;
02096       ast_moh_stop(chan);
02097    } else if (sentringing) {
02098       sentringing = 0;
02099       ast_indicate(chan, -1);
02100    }
02101 
02102    if (delprivintro && ast_fileexists(pa.privintro, NULL, NULL) > 0) {
02103       ast_filedelete(pa.privintro, NULL);
02104       if (ast_fileexists(pa.privintro, NULL, NULL) > 0) {
02105          ast_log(LOG_NOTICE, "privacy: ast_filedelete didn't do its job on %s\n", pa.privintro);
02106       } else {
02107          ast_verb(3, "Successfully deleted %s intro file\n", pa.privintro);
02108       }
02109    }
02110 
02111    ast_channel_early_bridge(chan, NULL);
02112    hanguptree(outgoing, NULL, 0); /* In this case, there's no answer anywhere */
02113    pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
02114    senddialendevent(chan, pa.status);
02115    ast_debug(1, "Exiting with DIALSTATUS=%s.\n", pa.status);
02116    
02117    if ((ast_test_flag64(peerflags, OPT_GO_ON)) && !ast_check_hangup(chan) && (res != AST_PBX_INCOMPLETE)) {
02118       if (!ast_tvzero(calldurationlimit))
02119          memset(&chan->whentohangup, 0, sizeof(chan->whentohangup));
02120       res = 0;
02121    }
02122 
02123 done:
02124    if (config.warning_sound) {
02125       ast_free((char *)config.warning_sound);
02126    }
02127    if (config.end_sound) {
02128       ast_free((char *)config.end_sound);
02129    }
02130    if (config.start_sound) {
02131       ast_free((char *)config.start_sound);
02132    }
02133    return res;
02134 }

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

helper function for wait_for_answer()

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

Definition at line 498 of file app_dial.c.

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

Referenced by wait_for_answer().

00500 {
00501    char tmpchan[256];
00502    struct ast_channel *original = o->chan;
00503    struct ast_channel *c = o->chan; /* the winner */
00504    struct ast_channel *in = num->chan; /* the input channel */
00505    char *stuff;
00506    char *tech;
00507    int cause;
00508 
00509    ast_copy_string(tmpchan, c->call_forward, sizeof(tmpchan));
00510    if ((stuff = strchr(tmpchan, '/'))) {
00511       *stuff++ = '\0';
00512       tech = tmpchan;
00513    } else {
00514       const char *forward_context;
00515       ast_channel_lock(c);
00516       forward_context = pbx_builtin_getvar_helper(c, "FORWARD_CONTEXT");
00517       if (ast_strlen_zero(forward_context)) {
00518          forward_context = NULL;
00519       }
00520       snprintf(tmpchan, sizeof(tmpchan), "%s@%s", c->call_forward, forward_context ? forward_context : c->context);
00521       ast_channel_unlock(c);
00522       stuff = tmpchan;
00523       tech = "Local";
00524    }
00525    /* Before processing channel, go ahead and check for forwarding */
00526    ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, c->name);
00527    /* If we have been told to ignore forwards, just set this channel to null and continue processing extensions normally */
00528    if (ast_test_flag64(peerflags, OPT_IGNORE_FORWARDING)) {
00529       ast_verb(3, "Forwarding %s to '%s/%s' prevented.\n", in->name, tech, stuff);
00530       c = o->chan = NULL;
00531       cause = AST_CAUSE_BUSY;
00532    } else {
00533       /* Setup parameters */
00534       c = o->chan = ast_request(tech, in->nativeformats, stuff, &cause);
00535       if (c) {
00536          if (single)
00537             ast_channel_make_compatible(o->chan, in);
00538          ast_channel_inherit_variables(in, o->chan);
00539          ast_channel_datastore_inherit(in, o->chan);
00540       } else
00541          ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
00542    }
00543    if (!c) {
00544       ast_clear_flag64(o, DIAL_STILLGOING);
00545       handle_cause(cause, num);
00546       ast_hangup(original);
00547    } else {
00548       char *new_cid_num, *new_cid_name;
00549       struct ast_channel *src;
00550 
00551       if (CAN_EARLY_BRIDGE(peerflags, c, in)) {
00552          ast_rtp_make_compatible(c, in, single);
00553       }
00554       if (ast_test_flag64(o, OPT_FORCECLID)) {
00555          new_cid_num = ast_strdup(S_OR(in->macroexten, in->exten));
00556          new_cid_name = NULL; /* XXX no name ? */
00557          src = c; /* XXX possible bug in previous code, which used 'winner' ? it may have changed */
00558       } else {
00559          new_cid_num = ast_strdup(in->cid.cid_num);
00560          new_cid_name = ast_strdup(in->cid.cid_name);
00561          src = in;
00562       }
00563       ast_string_field_set(c, accountcode, src->accountcode);
00564       c->cdrflags = src->cdrflags;
00565       S_REPLACE(c->cid.cid_num, new_cid_num);
00566       S_REPLACE(c->cid.cid_name, new_cid_name);
00567 
00568       if (in->cid.cid_ani) { /* XXX or maybe unconditional ? */
00569          S_REPLACE(c->cid.cid_ani, ast_strdup(in->cid.cid_ani));
00570       }
00571       S_REPLACE(c->cid.cid_rdnis, ast_strdup(S_OR(in->macroexten, in->exten)));
00572       if (ast_call(c, tmpchan, 0)) {
00573          ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
00574          ast_clear_flag64(o, DIAL_STILLGOING);
00575          ast_hangup(original);
00576          ast_hangup(c);
00577          c = o->chan = NULL;
00578          num->nochan++;
00579       } else {
00580          senddialevent(in, c, stuff);
00581          /* After calling, set callerid to extension */
00582          if (!ast_test_flag64(peerflags, OPT_ORIGINAL_CLID)) {
00583             char cidname[AST_MAX_EXTENSION] = "";
00584             ast_set_callerid(c, S_OR(in->macroexten, in->exten), get_cid_name(cidname, sizeof(cidname), in), NULL);
00585          }
00586          /* Hangup the original channel now, in case we needed it */
00587          ast_hangup(original);
00588       }
00589       if (single) {
00590          ast_indicate(in, -1);
00591       }
00592    }
00593 }

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

Definition at line 949 of file app_dial.c.

References ast_channel_lock, ast_channel_unlock, AST_FEATURE_PLAY_WARNING, ast_log(), ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_true(), ast_verb, chan, config, LOG_WARNING, pbx_builtin_getvar_helper(), S_OR, strsep(), and var.

Referenced by dial_exec_full().

00951 {
00952    char *stringp = ast_strdupa(parse);
00953    char *limit_str, *warning_str, *warnfreq_str;
00954    const char *var;
00955    int play_to_caller = 0, play_to_callee = 0;
00956    int delta;
00957 
00958    limit_str = strsep(&stringp, ":");
00959    warning_str = strsep(&stringp, ":");
00960    warnfreq_str = strsep(&stringp, ":");
00961 
00962    config->timelimit = atol(limit_str);
00963    if (warning_str)
00964       config->play_warning = atol(warning_str);
00965    if (warnfreq_str)
00966       config->warning_freq = atol(warnfreq_str);
00967 
00968    if (!config->timelimit) {
00969       ast_log(LOG_WARNING, "Dial does not accept L(%s), hanging up.\n", limit_str);
00970       config->timelimit = config->play_warning = config->warning_freq = 0;
00971       config->warning_sound = NULL;
00972       return -1; /* error */
00973    } else if ( (delta = config->play_warning - config->timelimit) > 0) {
00974       int w = config->warning_freq;
00975 
00976       /* If the first warning is requested _after_ the entire call would end,
00977          and no warning frequency is requested, then turn off the warning. If
00978          a warning frequency is requested, reduce the 'first warning' time by
00979          that frequency until it falls within the call's total time limit.
00980          Graphically:
00981               timelim->|    delta        |<-playwarning
00982          0__________________|_________________|
00983                 | w  |    |    |    |
00984 
00985          so the number of intervals to cut is 1+(delta-1)/w
00986       */
00987 
00988       if (w == 0) {
00989          config->play_warning = 0;
00990       } else {
00991          config->play_warning -= w * ( 1 + (delta-1)/w );
00992          if (config->play_warning < 1)
00993             config->play_warning = config->warning_freq = 0;
00994       }
00995    }
00996    
00997    ast_channel_lock(chan);
00998 
00999    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER");
01000 
01001    play_to_caller = var ? ast_true(var) : 1;
01002 
01003    var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE");
01004    play_to_callee = var ? ast_true(var) : 0;
01005 
01006    if (!play_to_caller && !play_to_callee)
01007       play_to_caller = 1;
01008 
01009    var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE");
01010    config->warning_sound = !ast_strlen_zero(var) ? ast_strdup(var) : ast_strdup("timeleft");
01011 
01012    /* The code looking at config wants a NULL, not just "", to decide
01013     * that the message should not be played, so we replace "" with NULL.
01014     * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is
01015     * not found.
01016     */
01017 
01018    var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE");
01019    config->end_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
01020 
01021    var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE");
01022    config->start_sound = !ast_strlen_zero(var) ? ast_strdup(var) : NULL;
01023 
01024    ast_channel_unlock(chan);
01025 
01026    /* undo effect of S(x) in case they are both used */
01027    calldurationlimit->tv_sec = 0;
01028    calldurationlimit->tv_usec = 0;
01029 
01030    /* more efficient to do it like S(x) does since no advanced opts */
01031    if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) {
01032       calldurationlimit->tv_sec = config->timelimit / 1000;
01033       calldurationlimit->tv_usec = (config->timelimit % 1000) * 1000;
01034       ast_verb(3, "Setting call duration limit to %.3lf seconds.\n",
01035          calldurationlimit->tv_sec + calldurationlimit->tv_usec / 1000000.0);
01036       config->timelimit = play_to_caller = play_to_callee =
01037       config->play_warning = config->warning_freq = 0;
01038    } else {
01039       ast_verb(3, "Limit Data for this call:\n");
01040       ast_verb(4, "timelimit      = %ld\n", config->timelimit);
01041       ast_verb(4, "play_warning   = %ld\n", config->play_warning);
01042       ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no");
01043       ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no");
01044       ast_verb(4, "warning_freq   = %ld\n", config->warning_freq);
01045       ast_verb(4, "start_sound    = %s\n", S_OR(config->start_sound, ""));
01046       ast_verb(4, "warning_sound  = %s\n", config->warning_sound);
01047       ast_verb(4, "end_sound      = %s\n", S_OR(config->end_sound, ""));
01048    }
01049    if (play_to_caller)
01050       ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
01051    if (play_to_callee)
01052       ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
01053    return 0;
01054 }

static void end_bridge_callback ( void *  data  )  [static]

Definition at line 1292 of file app_dial.c.

References ast_cdr::answer, ast_channel_lock, ast_channel_unlock, buf, ast_channel::cdr, chan, pbx_builtin_setvar_helper(), and ast_cdr::start.

Referenced by app_exec(), and dial_exec_full().

01293 {
01294    char buf[80];
01295    time_t end;
01296    struct ast_channel *chan = data;
01297 
01298    if (!chan->cdr) {
01299       return;
01300    }
01301 
01302    time(&end);
01303 
01304    ast_channel_lock(chan);
01305    if (chan->cdr->answer.tv_sec) {
01306       snprintf(buf, sizeof(buf), "%ld", (long) end - chan->cdr->answer.tv_sec);
01307       pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf);
01308    }
01309 
01310    if (chan->cdr->start.tv_sec) {
01311       snprintf(buf, sizeof(buf), "%ld", (long) end - chan->cdr->start.tv_sec);
01312       pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf);
01313    }
01314    ast_channel_unlock(chan);
01315 }

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

Definition at line 1317 of file app_dial.c.

References ast_bridge_config::end_bridge_callback_data.

Referenced by app_exec(), and dial_exec_full().

01317                                                                                                                                               {
01318    bconfig->end_bridge_callback_data = originator;
01319 }

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

Definition at line 458 of file app_dial.c.

References ast_get_hint(), chan, ast_channel::context, context, ast_channel::exten, exten, ast_channel::macrocontext, ast_channel::macroexten, and S_OR.

Referenced by dial_exec_full(), and do_forward().

00459 {
00460    const char *context = S_OR(chan->macrocontext, chan->context);
00461    const char *exten = S_OR(chan->macroexten, chan->exten);
00462 
00463    return ast_get_hint(NULL, 0, name, namelen, chan, context, exten) ? name : "";
00464 }

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

Definition at line 393 of file app_dial.c.

References AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, AST_CAUSE_NO_ANSWER, AST_CAUSE_NO_ROUTE_DESTINATION, AST_CAUSE_NORMAL_CLEARING, AST_CAUSE_UNREGISTERED, ast_cdr_busy(), ast_cdr_failed(), ast_cdr_noanswer(), ast_channel::cdr, and num.

00394 {
00395    struct ast_cdr *cdr = num->chan->cdr;
00396 
00397    switch(cause) {
00398    case AST_CAUSE_BUSY:
00399       if (cdr)
00400          ast_cdr_busy(cdr);
00401       num->busy++;
00402       break;
00403 
00404    case AST_CAUSE_CONGESTION:
00405       if (cdr)
00406          ast_cdr_failed(cdr);
00407       num->congestion++;
00408       break;
00409 
00410    case AST_CAUSE_NO_ROUTE_DESTINATION:
00411    case AST_CAUSE_UNREGISTERED:
00412       if (cdr)
00413          ast_cdr_failed(cdr);
00414       num->nochan++;
00415       break;
00416 
00417    case AST_CAUSE_NO_ANSWER:
00418       if (cdr) {
00419          ast_cdr_noanswer(cdr);
00420       }
00421       break;
00422    case AST_CAUSE_NORMAL_CLEARING:
00423       break;
00424 
00425    default:
00426       num->nochan++;
00427       break;
00428    }
00429 }

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

Definition at line 364 of file app_dial.c.

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

Referenced by dial_exec_full().

00365 {
00366    /* Hang up a tree of stuff */
00367    struct chanlist *oo;
00368    while (outgoing) {
00369       /* Hangup any existing lines we have open */
00370       if (outgoing->chan && (outgoing->chan != exception)) {
00371          if (answered_elsewhere)
00372             ast_set_flag(outgoing->chan, AST_FLAG_ANSWERED_ELSEWHERE);
00373          ast_hangup(outgoing->chan);
00374       }
00375       oo = outgoing;
00376       outgoing = outgoing->next;
00377       ast_free(oo);
00378    }
00379 }

static int load_module ( void   )  [static]

Definition at line 2269 of file app_dial.c.

References ast_add_extension2(), ast_context_find_or_create(), ast_free_ptr, ast_log(), ast_register_application, ast_strdup, dial_exec(), LOG_ERROR, and retrydial_exec().

02270 {
02271    int res;
02272    struct ast_context *con;
02273 
02274    con = ast_context_find_or_create(NULL, NULL, "app_dial_gosub_virtual_context", "app_dial");
02275    if (!con)
02276       ast_log(LOG_ERROR, "Dial virtual context 'app_dial_gosub_virtual_context' does not exist and unable to create\n");
02277    else
02278       ast_add_extension2(con, 1, "s", 1, NULL, NULL, "NoOp", ast_strdup(""), ast_free_ptr, "app_dial");
02279 
02280    res = ast_register_application(app, dial_exec, synopsis, descrip);
02281    res |= ast_register_application(rapp, retrydial_exec, rsynopsis, rdescrip);
02282 
02283    return res;
02284 }

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

Definition at line 439 of file app_dial.c.

References ast_goto_if_exists(), ast_strlen_zero(), chan, ast_channel::context, and ast_channel::macrocontext.

Referenced by retrydial_exec().

00440 {
00441    char rexten[2] = { exten, '\0' };
00442 
00443    if (context) {
00444       if (!ast_goto_if_exists(chan, context, rexten, pri))
00445          return 1;
00446    } else {
00447       if (!ast_goto_if_exists(chan, chan->context, rexten, pri))
00448          return 1;
00449       else if (!ast_strlen_zero(chan->macrocontext)) {
00450          if (!ast_goto_if_exists(chan, chan->macrocontext, rexten, pri))
00451             return 1;
00452       }
00453    }
00454    return 0;
00455 }

static void replace_macro_delimiter ( char *  s  )  [static]

Definition at line 930 of file app_dial.c.

Referenced by dial_exec_full().

00931 {
00932    for (; *s; s++)
00933       if (*s == '^')
00934          *s = ',';
00935 }

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

Definition at line 2145 of file app_dial.c.

References AST_APP_ARG, ast_channel_lock, ast_channel_unlock, AST_DECLARE_APP_ARGS, AST_DIGIT_ANY, ast_fileexists(), AST_FLAG_MOH, ast_log(), ast_moh_start(), ast_moh_stop(), AST_PBX_INCOMPLETE, AST_STANDARD_APP_ARGS, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_test_flag64, ast_waitfordigit(), ast_waitstream(), chan, ast_channel::data, dial_exec_full(), LOG_ERROR, LOG_WARNING, onedigit_goto(), OPT_DTMF_EXIT, parse(), and pbx_builtin_getvar_helper().

Referenced by load_module().

02146 {
02147    char *parse;
02148    const char *context = NULL;
02149    int sleepms = 0, loops = 0, res = -1;
02150    struct ast_flags64 peerflags = { 0, };
02151    AST_DECLARE_APP_ARGS(args,
02152       AST_APP_ARG(announce);
02153       AST_APP_ARG(sleep);
02154       AST_APP_ARG(retries);
02155       AST_APP_ARG(dialdata);
02156    );
02157 
02158    if (ast_strlen_zero(data)) {
02159       ast_log(LOG_WARNING, "RetryDial requires an argument!\n");
02160       return -1;
02161    }
02162 
02163    parse = ast_strdupa(data);
02164    AST_STANDARD_APP_ARGS(args, parse);
02165 
02166    if (!ast_strlen_zero(args.sleep) && (sleepms = atoi(args.sleep)))
02167       sleepms *= 1000;
02168 
02169    if (!ast_strlen_zero(args.retries)) {
02170       loops = atoi(args.retries);
02171    }
02172 
02173    if (!args.dialdata) {
02174       ast_log(LOG_ERROR, "%s requires a 4th argument (dialdata)\n", rapp);
02175       goto done;
02176    }
02177 
02178    if (sleepms < 1000)
02179       sleepms = 10000;
02180 
02181    if (!loops)
02182       loops = -1; /* run forever */
02183 
02184    ast_channel_lock(chan);
02185    context = pbx_builtin_getvar_helper(chan, "EXITCONTEXT");
02186    context = !ast_strlen_zero(context) ? ast_strdupa(context) : NULL;
02187    ast_channel_unlock(chan);
02188 
02189    res = 0;
02190    while (loops) {
02191       int continue_exec;
02192 
02193       chan->data = "Retrying";
02194       if (ast_test_flag(chan, AST_FLAG_MOH))
02195          ast_moh_stop(chan);
02196 
02197       res = dial_exec_full(chan, args.dialdata, &peerflags, &continue_exec);
02198       if (continue_exec)
02199          break;
02200 
02201       if (res == 0) {
02202          if (ast_test_flag64(&peerflags, OPT_DTMF_EXIT)) {
02203             if (!ast_strlen_zero(args.announce)) {
02204                if (ast_fileexists(args.announce, NULL, chan->language) > 0) {
02205                   if (!(res = ast_streamfile(chan, args.announce, chan->language)))
02206                      ast_waitstream(chan, AST_DIGIT_ANY);
02207                } else
02208                   ast_log(LOG_WARNING, "Announce file \"%s\" specified in Retrydial does not exist\n", args.announce);
02209             }
02210             if (!res && sleepms) {
02211                if (!ast_test_flag(chan, AST_FLAG_MOH))
02212                   ast_moh_start(chan, NULL, NULL);
02213                res = ast_waitfordigit(chan, sleepms);
02214             }
02215          } else {
02216             if (!ast_strlen_zero(args.announce)) {
02217                if (ast_fileexists(args.announce, NULL, chan->language) > 0) {
02218                   if (!(res = ast_streamfile(chan, args.announce, chan->language)))
02219                      res = ast_waitstream(chan, "");
02220                } else
02221                   ast_log(LOG_WARNING, "Announce file \"%s\" specified in Retrydial does not exist\n", args.announce);
02222             }
02223             if (sleepms) {
02224                if (!ast_test_flag(chan, AST_FLAG_MOH))
02225                   ast_moh_start(chan, NULL, NULL);
02226                if (!res)
02227                   res = ast_waitfordigit(chan, sleepms);
02228             }
02229          }
02230       }
02231 
02232       if (res < 0 || res == AST_PBX_INCOMPLETE) {
02233          break;
02234       } else if (res > 0) { /* Trying to send the call elsewhere (1 digit ext) */
02235          if (onedigit_goto(chan, context, (char) res, 1)) {
02236             res = 0;
02237             break;
02238          }
02239       }
02240       loops--;
02241    }
02242    if (loops == 0)
02243       res = 0;
02244    else if (res == 1)
02245       res = 0;
02246 
02247    if (ast_test_flag(chan, AST_FLAG_MOH))
02248       ast_moh_stop(chan);
02249  done:
02250    return res;
02251 }

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

Definition at line 482 of file app_dial.c.

References EVENT_FLAG_CALL, manager_event, and ast_cdr::src.

Referenced by dial_exec_full().

00483 {
00484    manager_event(EVENT_FLAG_CALL, "Dial",
00485       "SubEvent: End\r\n"
00486       "Channel: %s\r\n"
00487       "UniqueID: %s\r\n"
00488       "DialStatus: %s\r\n",
00489       src->name, src->uniqueid, dialstatus);
00490 }

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

Definition at line 466 of file app_dial.c.

References ast_cdr::dst, EVENT_FLAG_CALL, manager_event, S_OR, and ast_cdr::src.

Referenced by dial_exec_full(), and do_forward().

00467 {
00468    manager_event(EVENT_FLAG_CALL, "Dial",
00469       "SubEvent: Begin\r\n"
00470       "Channel: %s\r\n"
00471       "Destination: %s\r\n"
00472       "CallerIDNum: %s\r\n"
00473       "CallerIDName: %s\r\n"
00474       "UniqueID: %s\r\n"
00475       "DestUniqueID: %s\r\n"
00476       "Dialstring: %s\r\n",
00477       src->name, dst->name, S_OR(src->cid.cid_num, "<unknown>"),
00478       S_OR(src->cid.cid_name, "<unknown>"), src->uniqueid,
00479       dst->uniqueid, dialstring ? dialstring : "");
00480 }

static int setup_privacy_args ( struct privacy_args pa,
struct ast_flags64 opts,
char *  opt_args[],
struct ast_channel chan 
) [static]

returns 1 if successful, 0 or <0 if the caller should 'goto out'

Definition at line 1191 of file app_dial.c.

References ast_answer(), ast_config_AST_DATA_DIR, ast_copy_string(), ast_dsp_get_threshold_from_settings(), ast_filedelete(), ast_fileexists(), ast_log(), ast_mkdir(), ast_play_and_record(), AST_PRIVACY_ALLOW, ast_privacy_check(), AST_PRIVACY_DENY, AST_PRIVACY_KILL, AST_PRIVACY_TORTURE, AST_PRIVACY_UNKNOWN, ast_shrink_phone_number(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag64, ast_verb, ast_waitstream(), chan, ast_channel::cid, ast_callerid::cid_num, ast_channel::exten, ast_channel::language, LOG_NOTICE, LOG_WARNING, ast_channel::name, OPT_ARG_PRIVACY, OPT_PRIVACY, OPT_SCREEN_NOCLID, privacy_args::privcid, privacy_args::privdb_val, privacy_args::privintro, silencethreshold, privacy_args::status, and THRESHOLD_SILENCE.

Referenced by dial_exec_full().

01193 {
01194    char callerid[60];
01195    int res;
01196    char *l;
01197    int silencethreshold;
01198 
01199    if (!ast_strlen_zero(chan->cid.cid_num)) {
01200       l = ast_strdupa(chan->cid.cid_num);
01201       ast_shrink_phone_number(l);
01202       if (ast_test_flag64(opts, OPT_PRIVACY) ) {
01203          ast_verb(3, "Privacy DB is '%s', clid is '%s'\n", opt_args[OPT_ARG_PRIVACY], l);
01204          pa->privdb_val = ast_privacy_check(opt_args[OPT_ARG_PRIVACY], l);
01205       } else {
01206          ast_verb(3, "Privacy Screening, clid is '%s'\n", l);
01207          pa->privdb_val = AST_PRIVACY_UNKNOWN;
01208       }
01209    } else {
01210       char *tnam, *tn2;
01211 
01212       tnam = ast_strdupa(chan->name);
01213       /* clean the channel name so slashes don't try to end up in disk file name */
01214       for (tn2 = tnam; *tn2; tn2++) {
01215          if (*tn2 == '/')  /* any other chars to be afraid of? */
01216             *tn2 = '=';
01217       }
01218       ast_verb(3, "Privacy-- callerid is empty\n");
01219 
01220       snprintf(callerid, sizeof(callerid), "NOCALLERID_%s%s", chan->exten, tnam);
01221       l = callerid;
01222       pa->privdb_val = AST_PRIVACY_UNKNOWN;
01223    }
01224 
01225    ast_copy_string(pa->privcid, l, sizeof(pa->privcid));
01226 
01227    if (strncmp(pa->privcid, "NOCALLERID", 10) != 0 && ast_test_flag64(opts, OPT_SCREEN_NOCLID)) {
01228       /* if callerid is set and OPT_SCREEN_NOCLID is set also */
01229       ast_verb(3, "CallerID set (%s); N option set; Screening should be off\n", pa->privcid);
01230       pa->privdb_val = AST_PRIVACY_ALLOW;
01231    } else if (ast_test_flag64(opts, OPT_SCREEN_NOCLID) && strncmp(pa->privcid, "NOCALLERID", 10) == 0) {
01232       ast_verb(3, "CallerID blank; N option set; Screening should happen; dbval is %d\n", pa->privdb_val);
01233    }
01234    
01235    if (pa->privdb_val == AST_PRIVACY_DENY) {
01236       ast_verb(3, "Privacy DB reports PRIVACY_DENY for this callerid. Dial reports unavailable\n");
01237       ast_copy_string(pa->status, "NOANSWER", sizeof(pa->status));
01238       return 0;
01239    } else if (pa->privdb_val == AST_PRIVACY_KILL) {
01240       ast_copy_string(pa->status, "DONTCALL", sizeof(pa->status));
01241       return 0; /* Is this right? */
01242    } else if (pa->privdb_val == AST_PRIVACY_TORTURE) {
01243       ast_copy_string(pa->status, "TORTURE", sizeof(pa->status));
01244       return 0; /* is this right??? */
01245    } else if (pa->privdb_val == AST_PRIVACY_UNKNOWN) {
01246       /* Get the user's intro, store it in priv-callerintros/$CID,
01247          unless it is already there-- this should be done before the
01248          call is actually dialed  */
01249 
01250       /* make sure the priv-callerintros dir actually exists */
01251       snprintf(pa->privintro, sizeof(pa->privintro), "%s/sounds/priv-callerintros", ast_config_AST_DATA_DIR);
01252       if ((res = ast_mkdir(pa->privintro, 0755))) {
01253          ast_log(LOG_WARNING, "privacy: can't create directory priv-callerintros: %s\n", strerror(res));
01254          return -1;
01255       }
01256 
01257       snprintf(pa->privintro, sizeof(pa->privintro), "priv-callerintros/%s", pa->privcid);
01258       if (ast_fileexists(pa->privintro, NULL, NULL ) > 0 && strncmp(pa->privcid, "NOCALLERID", 10) != 0) {
01259          /* the DELUX version of this code would allow this caller the
01260             option to hear and retape their previously recorded intro.
01261          */
01262       } else {
01263          int duration; /* for feedback from play_and_wait */
01264          /* the file doesn't exist yet. Let the caller submit his
01265             vocal intro for posterity */
01266          /* priv-recordintro script:
01267 
01268             "At the tone, please say your name:"
01269 
01270          */
01271          silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
01272          ast_answer(chan);
01273          res = ast_play_and_record(chan, "priv-recordintro", pa->privintro, 4, "gsm", &duration, silencethreshold, 2000, 0);  /* NOTE: I've reduced the total time to 4 sec */
01274                            /* don't think we'll need a lock removed, we took care of
01275                               conflicts by naming the pa.privintro file */
01276          if (res == -1) {
01277             /* Delete the file regardless since they hung up during recording */
01278             ast_filedelete(pa->privintro, NULL);
01279             if (ast_fileexists(pa->privintro, NULL, NULL) > 0)
01280                ast_log(LOG_NOTICE, "privacy: ast_filedelete didn't do its job on %s\n", pa->privintro);
01281             else
01282                ast_verb(3, "Successfully deleted %s intro file\n", pa->privintro);
01283             return -1;
01284          }
01285          if (!ast_streamfile(chan, "vm-dialout", chan->language) )
01286             ast_waitstream(chan, "");
01287       }
01288    }
01289    return 1; /* success */
01290 }

static int unload_module ( void   )  [static]

Definition at line 2253 of file app_dial.c.

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

02254 {
02255    int res;
02256    struct ast_context *con;
02257 
02258    res = ast_unregister_application(app);
02259    res |= ast_unregister_application(rapp);
02260 
02261    if ((con = ast_context_find("app_dial_gosub_virtual_context"))) {
02262       ast_context_remove_extension2(con, "s", 1, NULL, 0);
02263       ast_context_destroy(con, "app_dial"); /* leave nothing behind */
02264    }
02265 
02266    return res;
02267 }

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

Definition at line 938 of file app_dial.c.

References ast_test_flag64, OPT_PRIVACY, and OPT_SCREENING.

00939 {
00940    if (res < '1')
00941       return 0;
00942    if (ast_test_flag64(opts, OPT_PRIVACY) && res <= '5')
00943       return 1;
00944    if (ast_test_flag64(opts, OPT_SCREENING) && res <= '4')
00945       return 1;
00946    return 0;
00947 }

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

Definition at line 604 of file app_dial.c.

References ast_channel::_state, ast_cdr::answer, AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, AST_CAUSE_NORMAL_CLEARING, AST_CDR_ANSWERED, ast_channel_early_bridge(), ast_channel_make_compatible(), ast_channel_sendhtml(), ast_clear_flag64, AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HOLD, AST_CONTROL_OFFHOOK, AST_CONTROL_PROCEEDING, AST_CONTROL_PROGRESS, AST_CONTROL_RINGING, AST_CONTROL_SRCUPDATE, AST_CONTROL_UNHOLD, AST_CONTROL_VIDUPDATE, ast_copy_flags64, ast_copy_string(), ast_deactivate_generator(), ast_debug, AST_FRAME_CONTROL, AST_FRAME_HTML, AST_FRAME_IMAGE, AST_FRAME_TEXT, AST_FRAME_VOICE, ast_frfree, ast_hangup(), ast_indicate(), ast_log(), AST_MAX_WATCHERS, ast_poll_channel_add(), ast_poll_channel_del(), ast_read(), AST_STATE_UP, ast_str_alloca, ast_string_field_set, ast_strlen_zero(), ast_test_flag64, ast_tvnow(), ast_verb, ast_waitfor_n(), ast_write(), CAN_EARLY_BRIDGE, ast_channel::cdr, chanlist::chan, DIAL_NOFORWARDHTML, DIAL_STILLGOING, dialcontext, ast_cdr::disposition, do_forward(), f, FEATURE_MAX_LEN, handle_cause(), ast_channel::hangupcause, LOG_WARNING, ast_channel::name, chanlist::next, num, OPT_CALLEE_HANGUP, OPT_CALLEE_MIXMONITOR, OPT_CALLEE_MONITOR, OPT_CALLEE_PARK, OPT_CALLEE_TRANSFER, OPT_CALLER_HANGUP, OPT_CALLER_MIXMONITOR, OPT_CALLER_MONITOR, OPT_CALLER_PARK, OPT_CALLER_TRANSFER, OPT_MUSICBACK, OPT_RINGBACK, privacy_args::sentringing, and privacy_args::status.

Referenced by dial_exec_full(), and try_calling().

00608 {
00609    struct cause_args num = *num_in;
00610    int prestart = num.busy + num.congestion + num.nochan;
00611    int orig = *to;
00612    struct ast_channel *peer = NULL;
00613    /* single is set if only one destination is enabled */
00614    int single = outgoing && !outgoing->next && !ast_test_flag64(outgoing, OPT_MUSICBACK | OPT_RINGBACK);
00615 #ifdef HAVE_EPOLL
00616    struct chanlist *epollo;
00617 #endif
00618    struct ast_str *featurecode = ast_str_alloca(FEATURE_MAX_LEN + 1);
00619    if (single) {
00620       /* Turn off hold music, etc */
00621       ast_deactivate_generator(in);
00622       /* If we are calling a single channel, make them compatible for in-band tone purpose */
00623       ast_channel_make_compatible(outgoing->chan, in);
00624    }
00625 
00626 #ifdef HAVE_EPOLL
00627    for (epollo = outgoing; epollo; epollo = epollo->next)
00628       ast_poll_channel_add(in, epollo->chan);
00629 #endif
00630 
00631    while (*to && !peer) {
00632       struct chanlist *o;
00633       int pos = 0; /* how many channels do we handle */
00634       int numlines = prestart;
00635       struct ast_channel *winner;
00636       struct ast_channel *watchers[AST_MAX_WATCHERS];
00637 
00638       watchers[pos++] = in;
00639       for (o = outgoing; o; o = o->next) {
00640          /* Keep track of important channels */
00641          if (ast_test_flag64(o, DIAL_STILLGOING) && o->chan)
00642             watchers[pos++] = o->chan;
00643          numlines++;
00644       }
00645       if (pos == 1) { /* only the input channel is available */
00646          if (numlines == (num.busy + num.congestion + num.nochan)) {
00647             ast_verb(2, "Everyone is busy/congested at this time (%d:%d/%d/%d)\n", numlines, num.busy, num.congestion, num.nochan);
00648             if (num.busy)
00649                strcpy(pa->status, "BUSY");
00650             else if (num.congestion)
00651                strcpy(pa->status, "CONGESTION");
00652             else if (num.nochan)
00653                strcpy(pa->status, "CHANUNAVAIL");
00654          } else {
00655             ast_verb(3, "No one is available to answer at this time (%d:%d/%d/%d)\n", numlines, num.busy, num.congestion, num.nochan);
00656          }
00657          *to = 0;
00658          return NULL;
00659       }
00660       winner = ast_waitfor_n(watchers, pos, to);
00661       for (o = outgoing; o; o = o->next) {
00662          struct ast_frame *f;
00663          struct ast_channel *c = o->chan;
00664 
00665          if (c == NULL)
00666             continue;
00667          if (ast_test_flag64(o, DIAL_STILLGOING) && c->_state == AST_STATE_UP) {
00668             if (!peer) {
00669                ast_verb(3, "%s answered %s\n", c->name, in->name);
00670                peer = c;
00671                ast_copy_flags64(peerflags, o,
00672                   OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
00673                   OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
00674                   OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
00675                   OPT_CALLEE_PARK | OPT_CALLER_PARK |
00676                   OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR |
00677                   DIAL_NOFORWARDHTML);
00678                ast_string_field_set(c, dialcontext, "");
00679                ast_copy_string(c->exten, "", sizeof(c->exten));
00680             }
00681             continue;
00682          }
00683          if (c != winner)
00684             continue;
00685          /* here, o->chan == c == winner */
00686          if (!ast_strlen_zero(c->call_forward)) {
00687             do_forward(o, &num, peerflags, single);
00688             continue;
00689          }
00690          f = ast_read(winner);
00691          if (!f) {
00692             in->hangupcause = c->hangupcause;
00693 #ifdef HAVE_EPOLL
00694             ast_poll_channel_del(in, c);
00695 #endif
00696             ast_hangup(c);
00697             c = o->chan = NULL;
00698             ast_clear_flag64(o, DIAL_STILLGOING);
00699             handle_cause(in->hangupcause, &num);
00700             continue;
00701          }
00702          if (f->frametype == AST_FRAME_CONTROL) {
00703             switch(f->subclass) {
00704             case AST_CONTROL_ANSWER:
00705                /* This is our guy if someone answered. */
00706                if (!peer) {
00707                   ast_verb(3, "%s answered %s\n", c->name, in->name);
00708                   peer = c;
00709                   if (peer->cdr) {
00710                      peer->cdr->answer = ast_tvnow();
00711                      peer->cdr->disposition = AST_CDR_ANSWERED;
00712                   }
00713                   ast_copy_flags64(peerflags, o,
00714                      OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
00715                      OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
00716                      OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
00717                      OPT_CALLEE_PARK | OPT_CALLER_PARK |
00718                      OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR |
00719                      DIAL_NOFORWARDHTML);
00720                   ast_string_field_set(c, dialcontext, "");
00721                   ast_copy_string(c->exten, "", sizeof(c->exten));
00722                   if (CAN_EARLY_BRIDGE(peerflags, in, peer))
00723                      /* Setup early bridge if appropriate */
00724                      ast_channel_early_bridge(in, peer);
00725                }
00726                /* If call has been answered, then the eventual hangup is likely to be normal hangup */
00727                in->hangupcause = AST_CAUSE_NORMAL_CLEARING;
00728                c->hangupcause = AST_CAUSE_NORMAL_CLEARING;
00729                break;
00730             case AST_CONTROL_BUSY:
00731                ast_verb(3, "%s is busy\n", c->name);
00732                in->hangupcause = c->hangupcause;
00733                ast_hangup(c);
00734                c = o->chan = NULL;
00735                ast_clear_flag64(o, DIAL_STILLGOING);
00736                handle_cause(AST_CAUSE_BUSY, &num);
00737                break;
00738             case AST_CONTROL_CONGESTION:
00739                ast_verb(3, "%s is circuit-busy\n", c->name);
00740                in->hangupcause = c->hangupcause;
00741                ast_hangup(c);
00742                c = o->chan = NULL;
00743                ast_clear_flag64(o, DIAL_STILLGOING);
00744                handle_cause(AST_CAUSE_CONGESTION, &num);
00745                break;
00746             case AST_CONTROL_RINGING:
00747                ast_verb(3, "%s is ringing\n", c->name);
00748                /* Setup early media if appropriate */
00749                if (single && CAN_EARLY_BRIDGE(peerflags, in, c))
00750                   ast_channel_early_bridge(in, c);
00751                if (!(pa->sentringing) && !ast_test_flag64(outgoing, OPT_MUSICBACK)) {
00752                   ast_indicate(in, AST_CONTROL_RINGING);
00753                   pa->sentringing++;
00754                }
00755                break;
00756             case AST_CONTROL_PROGRESS:
00757                ast_verb(3, "%s is making progress passing it to %s\n", c->name, in->name);
00758                /* Setup early media if appropriate */
00759                if (single && CAN_EARLY_BRIDGE(peerflags, in, c))
00760                   ast_channel_early_bridge(in, c);
00761                if (!ast_test_flag64(outgoing, OPT_RINGBACK))
00762                   if (single || (!single && !pa->sentringing)) {
00763                      ast_indicate(in, AST_CONTROL_PROGRESS);
00764                   }
00765                break;
00766             case AST_CONTROL_VIDUPDATE:
00767                ast_verb(3, "%s requested a video update, passing it to %s\n", c->name, in->name);
00768                ast_indicate(in, AST_CONTROL_VIDUPDATE);
00769                break;
00770             case AST_CONTROL_SRCUPDATE:
00771                ast_verb(3, "%s requested a source update, passing it to %s\n", c->name, in->name);
00772                ast_indicate(in, AST_CONTROL_SRCUPDATE);
00773                break;
00774             case AST_CONTROL_PROCEEDING:
00775                ast_verb(3, "%s is proceeding passing it to %s\n", c->name, in->name);
00776                if (single && CAN_EARLY_BRIDGE(peerflags, in, c))
00777                   ast_channel_early_bridge(in, c);
00778                if (!ast_test_flag64(outgoing, OPT_RINGBACK))
00779                   ast_indicate(in, AST_CONTROL_PROCEEDING);
00780                break;
00781             case AST_CONTROL_HOLD:
00782                ast_verb(3, "Call on %s placed on hold\n", c->name);
00783                ast_indicate(in, AST_CONTROL_HOLD);
00784                break;
00785             case AST_CONTROL_UNHOLD:
00786                ast_verb(3, "Call on %s left from hold\n", c->name);
00787                ast_indicate(in, AST_CONTROL_UNHOLD);
00788                break;
00789             case AST_CONTROL_OFFHOOK:
00790             case AST_CONTROL_FLASH:
00791                /* Ignore going off hook and flash */
00792                break;
00793             case -1:
00794                if (!ast_test_flag64(outgoing, OPT_RINGBACK | OPT_MUSICBACK)) {
00795                   ast_verb(3, "%s stopped sounds\n", c->name);
00796                   ast_indicate(in, -1);
00797                   pa->sentringing = 0;
00798                }
00799                break;
00800             default:
00801                ast_debug(1, "Dunno what to do with control type %d\n", f->subclass);
00802             }
00803          } else if (single) {
00804             switch (f->frametype) {
00805                case AST_FRAME_VOICE:
00806                case AST_FRAME_IMAGE:
00807                case AST_FRAME_TEXT:
00808                   if (ast_write(in, f)) {
00809                      ast_log(LOG_WARNING, "Unable to write frame\n");
00810                   }
00811                   break;
00812                case AST_FRAME_HTML:
00813                   if (!ast_test_flag64(outgoing, DIAL_NOFORWARDHTML) && ast_channel_sendhtml(in, f->subclass, f->data.ptr, f->datalen) == -1) {
00814                      ast_log(LOG_WARNING, "Unable to send URL\n");
00815                   }
00816                   break;
00817                default:
00818                   break;
00819             }
00820          }
00821          ast_frfree(f);
00822       } /* end for */
00823       if (winner == in) {
00824          struct ast_frame *f = ast_read(in);
00825 #if 0
00826          if (f && (f->frametype != AST_FRAME_VOICE))
00827             printf("Frame type: %d, %d\n", f->frametype, f->subclass);
00828          else if (!f || (f->frametype != AST_FRAME_VOICE))
00829             printf("Hangup received on %s\n", in->name);
00830 #endif
00831          if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
00832             /* Got hung up */
00833             *to = -1;
00834             strcpy(pa->status, "CANCEL");
00835             ast_cdr_noanswer(in->cdr);
00836             if (f) {
00837                if (f->data.uint32) {
00838                   in->hangupcause = f->data.uint32;
00839                }
00840                ast_frfree(f);
00841             }
00842             return NULL;
00843          }
00844 
00845          /* now f is guaranteed non-NULL */
00846          if (f->frametype == AST_FRAME_DTMF) {
00847             if (ast_test_flag64(peerflags, OPT_DTMF_EXIT)) {
00848                const char *context;
00849                ast_channel_lock(in);
00850                context = pbx_builtin_getvar_helper(in, "EXITCONTEXT");
00851                if (onedigit_goto(in, context, (char) f->subclass, 1)) {
00852                   ast_verb(3, "User hit %c to disconnect call.\n", f->subclass);
00853                   *to = 0;
00854                   ast_cdr_noanswer(in->cdr);
00855                   *result = f->subclass;
00856                   strcpy(pa->status, "CANCEL");
00857                   ast_frfree(f);
00858                   ast_channel_unlock(in);
00859                   return NULL;
00860                }
00861                ast_channel_unlock(in);
00862             }
00863 
00864             if (ast_test_flag64(peerflags, OPT_CALLER_HANGUP) &&
00865                detect_disconnect(in, f->subclass, featurecode)) {
00866                ast_verb(3, "User requested call disconnect.\n");
00867                *to = 0;
00868                strcpy(pa->status, "CANCEL");
00869                ast_cdr_noanswer(in->cdr);
00870                ast_frfree(f);
00871                return NULL;
00872             }
00873          }
00874 
00875          /* Forward HTML stuff */
00876          if (single && (f->frametype == AST_FRAME_HTML) && !ast_test_flag64(outgoing, DIAL_NOFORWARDHTML))
00877             if (ast_channel_sendhtml(outgoing->chan, f->subclass, f->data.ptr, f->datalen) == -1)
00878                ast_log(LOG_WARNING, "Unable to send URL\n");
00879 
00880          if (single && ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_DTMF_BEGIN) || (f->frametype == AST_FRAME_DTMF_END)))  {
00881             if (ast_write(outgoing->chan, f))
00882                ast_log(LOG_WARNING, "Unable to forward voice or dtmf\n");
00883          }
00884          if (single && (f->frametype == AST_FRAME_CONTROL) &&
00885             ((f->subclass == AST_CONTROL_HOLD) ||
00886             (f->subclass == AST_CONTROL_UNHOLD) ||
00887             (f->subclass == AST_CONTROL_VIDUPDATE) ||
00888              (f->subclass == AST_CONTROL_SRCUPDATE))) {
00889             ast_verb(3, "%s requested special control %d, passing it to %s\n", in->name, f->subclass, outgoing->chan->name);
00890             ast_indicate_data(outgoing->chan, f->subclass, f->data.ptr, f->datalen);
00891          }
00892          ast_frfree(f);
00893       }
00894       if (!*to)
00895          ast_verb(3, "Nobody picked up in %d ms\n", orig);
00896       if (!*to || ast_check_hangup(in))
00897          ast_cdr_noanswer(in->cdr);
00898    }
00899 
00900 #ifdef HAVE_EPOLL
00901    for (epollo = outgoing; epollo; epollo = epollo->next) {
00902       if (epollo->chan)
00903          ast_poll_channel_del(in, epollo->chan);
00904    }
00905 #endif
00906 
00907    return peer;
00908 }


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

Definition at line 2286 of file app_dial.c.

char* app = "Dial" [static]

Definition at line 65 of file app_dial.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 2286 of file app_dial.c.

char* descrip [static]

Definition at line 69 of file app_dial.c.

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

Definition at line 345 of file app_dial.c.

Referenced by dial_exec_full().

char* rapp = "RetryDial" [static]

Definition at line 240 of file app_dial.c.

char* rdescrip [static]

Definition at line 242 of file app_dial.c.

char* rsynopsis = "Place a call, retrying on failure allowing optional exit extension." [static]

Definition at line 241 of file app_dial.c.

char* synopsis = "Place a call and connect to the current channel" [static]

Definition at line 67 of file app_dial.c.


Generated on Wed Aug 18 22:33:58 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7