Fri Jul 24 00:41:08 2009

Asterisk developer's documentation


app_dial.c File Reference

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

#include "asterisk.h"
#include <sys/time.h>
#include <sys/signal.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include "asterisk/paths.h"
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/say.h"
#include "asterisk/config.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/callerid.h"
#include "asterisk/utils.h"
#include "asterisk/app.h"
#include "asterisk/causes.h"
#include "asterisk/rtp.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_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 }, [ '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 372 of file app_dial.c.

#define CAN_EARLY_BRIDGE ( flags,
chan,
peer   ) 

Value:

Definition at line 339 of file app_dial.c.

Referenced by wait_for_answer().

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

Definition at line 282 of file app_dial.c.

Referenced by dial_exec_full(), and wait_for_answer().

#define DIAL_STILLGOING   (1 << 31)

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

Referenced by dial_exec_full().

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

Definition at line 283 of file app_dial.c.

Referenced by dial_exec_full().

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

Definition at line 284 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 418 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 248 of file app_dial.c.

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

anonymous enum

Enumerator:
OPT_ARG_ANNOUNCE 
OPT_ARG_SENDDTMF 
OPT_ARG_GOTO 
OPT_ARG_DURATION_LIMIT 
OPT_ARG_MUSICBACK 
OPT_ARG_CALLEE_MACRO 
OPT_ARG_CALLEE_GOSUB 
OPT_ARG_CALLEE_GO_ON 
OPT_ARG_PRIVACY 
OPT_ARG_DURATION_STOP 
OPT_ARG_OPERMODE 
OPT_ARG_ARRAY_SIZE 

Definition at line 287 of file app_dial.c.

00287      {
00288    OPT_ARG_ANNOUNCE = 0,
00289    OPT_ARG_SENDDTMF,
00290    OPT_ARG_GOTO,
00291    OPT_ARG_DURATION_LIMIT,
00292    OPT_ARG_MUSICBACK,
00293    OPT_ARG_CALLEE_MACRO,
00294    OPT_ARG_CALLEE_GOSUB,
00295    OPT_ARG_CALLEE_GO_ON,
00296    OPT_ARG_PRIVACY,
00297    OPT_ARG_DURATION_STOP,
00298    OPT_ARG_OPERMODE,
00299    /* note: this entry _MUST_ be the last one in the enum */
00300    OPT_ARG_ARRAY_SIZE,
00301 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 2195 of file app_dial.c.

static void __unreg_module ( void   )  [static]

Definition at line 2195 of file app_dial.c.

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

Definition at line 889 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.

00890 {
00891    struct ast_flags features = { AST_FEATURE_DISCONNECT }; /* only concerned with disconnect feature */
00892    struct ast_call_feature feature = { 0, };
00893    int res;
00894 
00895    ast_str_append(&featurecode, 1, "%c", code);
00896 
00897    res = ast_feature_detect(chan, &features, ast_str_buffer(featurecode), &feature);
00898 
00899    if (res != AST_FEATURE_RETURN_STOREDIGITS) {
00900       ast_str_reset(featurecode);
00901    }
00902    if (feature.feature_mask & AST_FEATURE_DISCONNECT) {
00903       return 1;
00904    }
00905 
00906    return 0;
00907 }

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

Definition at line 2045 of file app_dial.c.

References chan, and dial_exec_full().

Referenced by load_module().

02046 {
02047    struct ast_flags64 peerflags;
02048 
02049    memset(&peerflags, 0, sizeof(peerflags));
02050 
02051    return dial_exec_full(chan, data, &peerflags, NULL);
02052 }

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

Definition at line 1300 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_CONTROL_PROGRESS, AST_CONTROL_RINGING, ast_copy_flags64, ast_copy_string(), ast_datastore_alloc(), ast_datastore_free(), ast_deactivate_generator(), ast_debug, AST_DECLARE_APP_ARGS, AST_DIGIT_ANY, ast_dtmf_stream(), ast_exists_extension(), AST_FEATURE_AUTOMIXMON, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_NO_H_EXTEN, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, AST_FLAG_IN_AUTOLOOP, ast_free, ast_hangup(), ast_indicate(), AST_LIST_HEAD, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_EXTENSION, ast_moh_start(), ast_moh_stop(), AST_OPTION_OPRMODE, ast_parseable_goto(), AST_PBX_INCOMPLETE, ast_pbx_run_args(), ast_pbx_start(), AST_PRIVACY_UNKNOWN, ast_request(), ast_rtp_make_compatible(), ast_senddigit(), ast_set2_flag, ast_set2_flag64, ast_set_callerid(), ast_set_flag, ast_set_flag64, ast_spawn_extension(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdup, ast_strdupa, ast_streamfile(), ast_string_field_set, ast_strlen_zero(), ast_test_flag, ast_test_flag64, ast_tvadd(), ast_tvnow(), ast_tvzero(), ast_verb, ast_waitstream(), ast_channel::cdr, ast_channel::cdrflags, chanlist::chan, chan, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_ani2, ast_callerid::cid_name, ast_callerid::cid_num, ast_callerid::cid_pres, ast_callerid::cid_rdnis, ast_callerid::cid_tns, ast_callerid::cid_ton, config, ast_channel::context, ast_channel::data, ast_datastore::data, DATASTORE_INHERIT_FOREVER, di, dial_exec_options, DIAL_NOFORWARDHTML, DIAL_STILLGOING, dialcontext, dialed_interface_info, do_timelimit(), end_bridge_callback(), end_bridge_callback_data_fixup(), errno, ast_channel::exten, ast_flags64::flags, get_cid_name(), handle_cause(), ast_channel::hangupcause, hanguptree(), ast_datastore::inheritance, ast_channel::language, ast_dialed_interface::list, LOG_ERROR, LOG_WARNING, ast_channel::macrocontext, ast_channel::macroexten, oprmode::mode, moh, musicclass, ast_channel::musicclass, ast_channel::name, ast_channel::nativeformats, num, OPT_ANNOUNCE, OPT_ARG_ANNOUNCE, OPT_ARG_ARRAY_SIZE, OPT_ARG_CALLEE_GO_ON, OPT_ARG_CALLEE_GOSUB, OPT_ARG_CALLEE_MACRO, OPT_ARG_DURATION_LIMIT, OPT_ARG_DURATION_STOP, OPT_ARG_GOTO, OPT_ARG_OPERMODE, OPT_ARG_PRIVACY, OPT_ARG_SENDDTMF, OPT_CALLEE_GO_ON, OPT_CALLEE_GOSUB, OPT_CALLEE_HANGUP, OPT_CALLEE_MACRO, OPT_CALLEE_MIXMONITOR, OPT_CALLEE_MONITOR, OPT_CALLEE_PARK, OPT_CALLEE_TRANSFER, OPT_CALLER_HANGUP, OPT_CALLER_MIXMONITOR, OPT_CALLER_MONITOR, OPT_CALLER_PARK, OPT_CALLER_TRANSFER, OPT_CANCEL_ELSEWHERE, OPT_DTMF_EXIT, OPT_DURATION_LIMIT, OPT_DURATION_STOP, OPT_FORCECLID, OPT_GO_ON, OPT_GOTO, OPT_IGNORE_FORWARDING, OPT_MUSICBACK, OPT_OPERMODE, OPT_ORIGINAL_CLID, OPT_PEER_H, OPT_PRIVACY, OPT_RESETCDR, OPT_RINGBACK, OPT_SCREENING, OPT_SENDDTMF, parse(), pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), oprmode::peer, ast_channel::priority, privacy_args::privdb_val, replace_macro_delimiter(), S_OR, S_REPLACE, senddialendevent(), senddialevent(), privacy_args::sentringing, setup_privacy_args(), privacy_args::status, strsep(), ast_channel::tech, ast_channel::transfercapability, ast_channel_tech::type, url, wait_for_answer(), and ast_channel::whentohangup.

Referenced by dial_exec(), and retrydial_exec().

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

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

helper function for wait_for_answer()

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

Definition at line 484 of file app_dial.c.

References ast_channel::accountcode, accountcode, ast_call(), AST_CAUSE_BUSY, ast_channel_datastore_inherit(), ast_channel_inherit_variables(), ast_channel_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_test_flag64, ast_verb, ast_channel::call_forward, ast_channel::cdrflags, chanlist::chan, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_name, ast_callerid::cid_num, ast_callerid::cid_rdnis, ast_channel::context, DIAL_STILLGOING, ast_channel::exten, get_cid_name(), handle_cause(), LOG_NOTICE, ast_channel::macroexten, ast_channel::name, ast_channel::nativeformats, num, OPT_FORCECLID, OPT_IGNORE_FORWARDING, OPT_ORIGINAL_CLID, pbx_builtin_getvar_helper(), S_OR, S_REPLACE, senddialevent(), and ast_channel::tech.

Referenced by wait_for_answer().

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

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

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

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

static void end_bridge_callback ( void *  data  )  [static]

Definition at line 1271 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(), dial_exec_full(), and try_calling().

01272 {
01273    char buf[80];
01274    time_t end;
01275    struct ast_channel *chan = data;
01276 
01277    if (!chan->cdr) {
01278       return;
01279    }
01280 
01281    time(&end);
01282 
01283    ast_channel_lock(chan);
01284    if (chan->cdr->answer.tv_sec) {
01285       snprintf(buf, sizeof(buf), "%ld", end - chan->cdr->answer.tv_sec);
01286       pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf);
01287    }
01288 
01289    if (chan->cdr->start.tv_sec) {
01290       snprintf(buf, sizeof(buf), "%ld", end - chan->cdr->start.tv_sec);
01291       pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf);
01292    }
01293    ast_channel_unlock(chan);
01294 }

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

Definition at line 1296 of file app_dial.c.

References ast_bridge_config::end_bridge_callback_data.

Referenced by app_exec(), dial_exec_full(), and try_calling().

01296                                                                                                                                               {
01297    bconfig->end_bridge_callback_data = originator;
01298 }

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

Definition at line 444 of file app_dial.c.

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

Referenced by dial_exec_full(), and do_forward().

00445 {
00446    const char *context = S_OR(chan->macrocontext, chan->context);
00447    const char *exten = S_OR(chan->macroexten, chan->exten);
00448 
00449    return ast_get_hint(NULL, 0, name, namelen, chan, context, exten) ? name : "";
00450 }

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

Definition at line 384 of file app_dial.c.

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

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

00385 {
00386    struct ast_cdr *cdr = num->chan->cdr;
00387 
00388    switch(cause) {
00389    case AST_CAUSE_BUSY:
00390       if (cdr)
00391          ast_cdr_busy(cdr);
00392       num->busy++;
00393       break;
00394 
00395    case AST_CAUSE_CONGESTION:
00396       if (cdr)
00397          ast_cdr_failed(cdr);
00398       num->congestion++;
00399       break;
00400 
00401    case AST_CAUSE_NO_ROUTE_DESTINATION:
00402    case AST_CAUSE_UNREGISTERED:
00403       if (cdr)
00404          ast_cdr_failed(cdr);
00405       num->nochan++;
00406       break;
00407 
00408    case AST_CAUSE_NORMAL_CLEARING:
00409       break;
00410 
00411    default:
00412       num->nochan++;
00413       break;
00414    }
00415 }

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

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

00356 {
00357    /* Hang up a tree of stuff */
00358    struct chanlist *oo;
00359    while (outgoing) {
00360       /* Hangup any existing lines we have open */
00361       if (outgoing->chan && (outgoing->chan != exception)) {
00362          if (answered_elsewhere)
00363             ast_set_flag(outgoing->chan, AST_FLAG_ANSWERED_ELSEWHERE);
00364          ast_hangup(outgoing->chan);
00365       }
00366       oo = outgoing;
00367       outgoing = outgoing->next;
00368       ast_free(oo);
00369    }
00370 }

static int load_module ( void   )  [static]

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

02179 {
02180    int res;
02181    struct ast_context *con;
02182 
02183    con = ast_context_find_or_create(NULL, NULL, "app_dial_gosub_virtual_context", "app_dial");
02184    if (!con)
02185       ast_log(LOG_ERROR, "Dial virtual context 'app_dial_gosub_virtual_context' does not exist and unable to create\n");
02186    else
02187       ast_add_extension2(con, 1, "s", 1, NULL, NULL, "NoOp", ast_strdup(""), ast_free_ptr, "app_dial");
02188 
02189    res = ast_register_application(app, dial_exec, synopsis, descrip);
02190    res |= ast_register_application(rapp, retrydial_exec, rsynopsis, rdescrip);
02191 
02192    return res;
02193 }

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

Definition at line 425 of file app_dial.c.

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

Referenced by retrydial_exec().

00426 {
00427    char rexten[2] = { exten, '\0' };
00428 
00429    if (context) {
00430       if (!ast_goto_if_exists(chan, context, rexten, pri))
00431          return 1;
00432    } else {
00433       if (!ast_goto_if_exists(chan, chan->context, rexten, pri))
00434          return 1;
00435       else if (!ast_strlen_zero(chan->macrocontext)) {
00436          if (!ast_goto_if_exists(chan, chan->macrocontext, rexten, pri))
00437             return 1;
00438       }
00439    }
00440    return 0;
00441 }

static void replace_macro_delimiter ( char *  s  )  [static]

Definition at line 909 of file app_dial.c.

Referenced by dial_exec_full().

00910 {
00911    for (; *s; s++)
00912       if (*s == '^')
00913          *s = ',';
00914 }

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

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

02055 {
02056    char *parse;
02057    const char *context = NULL;
02058    int sleepms = 0, loops = 0, res = -1;
02059    struct ast_flags64 peerflags = { 0, };
02060    AST_DECLARE_APP_ARGS(args,
02061       AST_APP_ARG(announce);
02062       AST_APP_ARG(sleep);
02063       AST_APP_ARG(retries);
02064       AST_APP_ARG(dialdata);
02065    );
02066 
02067    if (ast_strlen_zero(data)) {
02068       ast_log(LOG_WARNING, "RetryDial requires an argument!\n");
02069       return -1;
02070    }
02071 
02072    parse = ast_strdupa(data);
02073    AST_STANDARD_APP_ARGS(args, parse);
02074 
02075    if (!ast_strlen_zero(args.sleep) && (sleepms = atoi(args.sleep)))
02076       sleepms *= 1000;
02077 
02078    if (!ast_strlen_zero(args.retries)) {
02079       loops = atoi(args.retries);
02080    }
02081 
02082    if (!args.dialdata) {
02083       ast_log(LOG_ERROR, "%s requires a 4th argument (dialdata)\n", rapp);
02084       goto done;
02085    }
02086 
02087    if (sleepms < 1000)
02088       sleepms = 10000;
02089 
02090    if (!loops)
02091       loops = -1; /* run forever */
02092 
02093    ast_channel_lock(chan);
02094    context = pbx_builtin_getvar_helper(chan, "EXITCONTEXT");
02095    context = !ast_strlen_zero(context) ? ast_strdupa(context) : NULL;
02096    ast_channel_unlock(chan);
02097 
02098    res = 0;
02099    while (loops) {
02100       int continue_exec;
02101 
02102       chan->data = "Retrying";
02103       if (ast_test_flag(chan, AST_FLAG_MOH))
02104          ast_moh_stop(chan);
02105 
02106       res = dial_exec_full(chan, args.dialdata, &peerflags, &continue_exec);
02107       if (continue_exec)
02108          break;
02109 
02110       if (res == 0) {
02111          if (ast_test_flag64(&peerflags, OPT_DTMF_EXIT)) {
02112             if (!ast_strlen_zero(args.announce)) {
02113                if (ast_fileexists(args.announce, NULL, chan->language) > 0) {
02114                   if (!(res = ast_streamfile(chan, args.announce, chan->language)))
02115                      ast_waitstream(chan, AST_DIGIT_ANY);
02116                } else
02117                   ast_log(LOG_WARNING, "Announce file \"%s\" specified in Retrydial does not exist\n", args.announce);
02118             }
02119             if (!res && sleepms) {
02120                if (!ast_test_flag(chan, AST_FLAG_MOH))
02121                   ast_moh_start(chan, NULL, NULL);
02122                res = ast_waitfordigit(chan, sleepms);
02123             }
02124          } else {
02125             if (!ast_strlen_zero(args.announce)) {
02126                if (ast_fileexists(args.announce, NULL, chan->language) > 0) {
02127                   if (!(res = ast_streamfile(chan, args.announce, chan->language)))
02128                      res = ast_waitstream(chan, "");
02129                } else
02130                   ast_log(LOG_WARNING, "Announce file \"%s\" specified in Retrydial does not exist\n", args.announce);
02131             }
02132             if (sleepms) {
02133                if (!ast_test_flag(chan, AST_FLAG_MOH))
02134                   ast_moh_start(chan, NULL, NULL);
02135                if (!res)
02136                   res = ast_waitfordigit(chan, sleepms);
02137             }
02138          }
02139       }
02140 
02141       if (res < 0 || res == AST_PBX_INCOMPLETE) {
02142          break;
02143       } else if (res > 0) { /* Trying to send the call elsewhere (1 digit ext) */
02144          if (onedigit_goto(chan, context, (char) res, 1)) {
02145             res = 0;
02146             break;
02147          }
02148       }
02149       loops--;
02150    }
02151    if (loops == 0)
02152       res = 0;
02153    else if (res == 1)
02154       res = 0;
02155 
02156    if (ast_test_flag(chan, AST_FLAG_MOH))
02157       ast_moh_stop(chan);
02158  done:
02159    return res;
02160 }

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

Definition at line 468 of file app_dial.c.

References EVENT_FLAG_CALL, manager_event, and ast_cdr::src.

Referenced by dial_exec_full().

00469 {
00470    manager_event(EVENT_FLAG_CALL, "Dial",
00471       "SubEvent: End\r\n"
00472       "Channel: %s\r\n"
00473       "UniqueID: %s\r\n"
00474       "DialStatus: %s\r\n",
00475       src->name, src->uniqueid, dialstatus);
00476 }

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

Definition at line 452 of file app_dial.c.

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

Referenced by dial_exec_full(), and do_forward().

00453 {
00454    manager_event(EVENT_FLAG_CALL, "Dial",
00455       "SubEvent: Begin\r\n"
00456       "Channel: %s\r\n"
00457       "Destination: %s\r\n"
00458       "CallerIDNum: %s\r\n"
00459       "CallerIDName: %s\r\n"
00460       "UniqueID: %s\r\n"
00461       "DestUniqueID: %s\r\n"
00462       "Dialstring: %s\r\n",
00463       src->name, dst->name, S_OR(src->cid.cid_num, "<unknown>"),
00464       S_OR(src->cid.cid_name, "<unknown>"), src->uniqueid,
00465       dst->uniqueid, dialstring ? dialstring : "");
00466 }

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

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

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

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

static int unload_module ( void   )  [static]

Definition at line 2162 of file app_dial.c.

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

02163 {
02164    int res;
02165    struct ast_context *con;
02166 
02167    res = ast_unregister_application(app);
02168    res |= ast_unregister_application(rapp);
02169 
02170    if ((con = ast_context_find("app_dial_gosub_virtual_context"))) {
02171       ast_context_remove_extension2(con, "s", 1, NULL, 0);
02172       ast_context_destroy(con, "app_dial"); /* leave nothing behind */
02173    }
02174 
02175    return res;
02176 }

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

Definition at line 917 of file app_dial.c.

References ast_test_flag64, OPT_PRIVACY, and OPT_SCREENING.

00918 {
00919    if (res < '1')
00920       return 0;
00921    if (ast_test_flag64(opts, OPT_PRIVACY) && res <= '5')
00922       return 1;
00923    if (ast_test_flag64(opts, OPT_SCREENING) && res <= '4')
00924       return 1;
00925    return 0;
00926 }

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

Definition at line 585 of file app_dial.c.

References ast_channel::_state, ast_cdr::answer, AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, AST_CAUSE_NORMAL_CLEARING, AST_CDR_ANSWERED, ast_channel_early_bridge(), ast_channel_make_compatible(), ast_channel_sendhtml(), ast_clear_flag64, AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HOLD, AST_CONTROL_OFFHOOK, AST_CONTROL_PROCEEDING, AST_CONTROL_PROGRESS, AST_CONTROL_RINGING, AST_CONTROL_SRCUPDATE, AST_CONTROL_UNHOLD, AST_CONTROL_VIDUPDATE, ast_copy_flags64, ast_copy_string(), ast_deactivate_generator(), ast_debug, AST_FRAME_CONTROL, AST_FRAME_HTML, AST_FRAME_IMAGE, AST_FRAME_TEXT, AST_FRAME_VOICE, ast_frfree, ast_hangup(), ast_indicate(), ast_log(), AST_MAX_WATCHERS, ast_poll_channel_add(), ast_poll_channel_del(), ast_read(), AST_STATE_UP, ast_str_alloca, ast_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().

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


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 2195 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 2195 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 }, [ '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 337 of file app_dial.c.

Referenced by dial_exec_full().

char* rapp = "RetryDial" [static]

Definition at line 233 of file app_dial.c.

char* rdescrip [static]

Definition at line 235 of file app_dial.c.

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

Definition at line 234 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 Fri Jul 24 00:41:08 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7