Sat Sep 16 05:47:49 2006

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 <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include "asterisk.h"
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/options.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/manager.h"
#include "asterisk/privacy.h"

Go to the source code of this file.

Data Structures

struct  localuser
 We define a custom "local user" structure because we use it not only for keeping track of what is in use but also for keeping track of who we're dialing. More...

Defines

#define AST_MAX_FORWARDS   8
#define AST_MAX_WATCHERS   256
#define DIAL_NOFORWARDHTML   (1 << 31)
#define DIAL_STILLGOING   (1 << 30)
#define HANDLE_CAUSE(cause, chan)

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_PRIORITY_JUMP = (1 << 8), 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)
}
enum  {
  OPT_ARG_ANNOUNCE = 0, OPT_ARG_SENDDTMF, OPT_ARG_GOTO, OPT_ARG_DURATION_LIMIT,
  OPT_ARG_MUSICBACK, OPT_ARG_CALLEE_MACRO, OPT_ARG_PRIVACY, OPT_ARG_DURATION_STOP,
  OPT_ARG_ARRAY_SIZE
}

Functions

 AST_APP_OPTIONS (dial_exec_options,{AST_APP_OPTION_ARG('A', OPT_ANNOUNCE, OPT_ARG_ANNOUNCE), AST_APP_OPTION('C', OPT_RESETCDR), AST_APP_OPTION('d', OPT_DTMF_EXIT), AST_APP_OPTION_ARG('D', OPT_SENDDTMF, OPT_ARG_SENDDTMF), AST_APP_OPTION('f', OPT_FORCECLID), AST_APP_OPTION('g', OPT_GO_ON), AST_APP_OPTION_ARG('G', OPT_GOTO, OPT_ARG_GOTO), AST_APP_OPTION('h', OPT_CALLEE_HANGUP), AST_APP_OPTION('H', OPT_CALLER_HANGUP), AST_APP_OPTION('j', OPT_PRIORITY_JUMP), AST_APP_OPTION_ARG('L', OPT_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT), AST_APP_OPTION_ARG('m', OPT_MUSICBACK, OPT_ARG_MUSICBACK), AST_APP_OPTION_ARG('M', OPT_CALLEE_MACRO, OPT_ARG_CALLEE_MACRO), AST_APP_OPTION('n', OPT_SCREEN_NOINTRO), AST_APP_OPTION('N', OPT_SCREEN_NOCLID), AST_APP_OPTION('o', OPT_ORIGINAL_CLID), AST_APP_OPTION('p', OPT_SCREENING), AST_APP_OPTION_ARG('P', OPT_PRIVACY, OPT_ARG_PRIVACY), AST_APP_OPTION('r', OPT_RINGBACK), AST_APP_OPTION_ARG('S', OPT_DURATION_STOP, OPT_ARG_DURATION_STOP), AST_APP_OPTION('t', OPT_CALLEE_TRANSFER), AST_APP_OPTION('T', OPT_CALLER_TRANSFER), AST_APP_OPTION('w', OPT_CALLEE_MONITOR), AST_APP_OPTION('W', OPT_CALLER_MONITOR),})
char * description (void)
 Provides a description of the module.
static int dial_exec (struct ast_channel *chan, void *data)
static int dial_exec_full (struct ast_channel *chan, void *data, struct ast_flags *peerflags)
static char * get_cid_name (char *name, int namelen, struct ast_channel *chan)
static void hanguptree (struct localuser *outgoing, struct ast_channel *exception)
char * key ()
 Returns the ASTERISK_GPL_KEY.
int load_module (void)
 Initialize the module.
static int onedigit_goto (struct ast_channel *chan, char *context, char exten, int pri)
static int retrydial_exec (struct ast_channel *chan, void *data)
static void senddialevent (struct ast_channel *src, struct ast_channel *dst)
int unload_module (void)
 Cleanup all module structures, sockets, etc.
int usecount (void)
 Provides a usecount.
static struct ast_channelwait_for_answer (struct ast_channel *in, struct localuser *outgoing, int *to, struct ast_flags *peerflags, int *sentringing, char *status, size_t statussize, int busystart, int nochanstart, int congestionstart, int priority_jump, int *result)

Variables

static char * app = "Dial"
static char * descrip
enum { ... }  dial_exec_option_args
enum { ... }  dial_exec_option_flags
 LOCAL_USER_DECL
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"
static char * tdesc = "Dialing Application"


Detailed Description

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

Definition in file app_dial.c.


Define Documentation

#define AST_MAX_FORWARDS   8

Definition at line 290 of file app_dial.c.

Referenced by dial_exec_full(), and wait_for_answer().

#define AST_MAX_WATCHERS   256

Definition at line 292 of file app_dial.c.

Referenced by wait_for_answer().

#define DIAL_NOFORWARDHTML   (1 << 31)

Definition at line 221 of file app_dial.c.

Referenced by dial_exec_full(), and wait_for_answer().

#define DIAL_STILLGOING   (1 << 30)

Definition at line 220 of file app_dial.c.

Referenced by dial_exec_full(), and wait_for_answer().

#define HANDLE_CAUSE ( cause,
chan   ) 

Definition at line 294 of file app_dial.c.

Referenced by dial_exec_full(), and wait_for_answer().


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_PRIORITY_JUMP 
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 

Definition at line 193 of file app_dial.c.

00193      {
00194    OPT_ANNOUNCE = (1 << 0),
00195    OPT_RESETCDR = (1 << 1),
00196    OPT_DTMF_EXIT = (1 << 2),
00197    OPT_SENDDTMF = (1 << 3),
00198    OPT_FORCECLID = (1 << 4),
00199    OPT_GO_ON = (1 << 5),
00200    OPT_CALLEE_HANGUP = (1 << 6),
00201    OPT_CALLER_HANGUP = (1 << 7),
00202    OPT_PRIORITY_JUMP = (1 << 8),
00203    OPT_DURATION_LIMIT = (1 << 9),
00204    OPT_MUSICBACK = (1 << 10),
00205    OPT_CALLEE_MACRO = (1 << 11),
00206    OPT_SCREEN_NOINTRO = (1 << 12),
00207    OPT_SCREEN_NOCLID = (1 << 13),
00208    OPT_ORIGINAL_CLID = (1 << 14),
00209    OPT_SCREENING = (1 << 15),
00210    OPT_PRIVACY = (1 << 16),
00211    OPT_RINGBACK = (1 << 17),
00212    OPT_DURATION_STOP = (1 << 18),
00213    OPT_CALLEE_TRANSFER = (1 << 19),
00214    OPT_CALLER_TRANSFER = (1 << 20),
00215    OPT_CALLEE_MONITOR = (1 << 21),
00216    OPT_CALLER_MONITOR = (1 << 22),
00217    OPT_GOTO = (1 << 23),
00218 } dial_exec_option_flags;

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_PRIVACY 
OPT_ARG_DURATION_STOP 
OPT_ARG_ARRAY_SIZE 

Definition at line 223 of file app_dial.c.

00223      {
00224    OPT_ARG_ANNOUNCE = 0,
00225    OPT_ARG_SENDDTMF,
00226    OPT_ARG_GOTO,
00227    OPT_ARG_DURATION_LIMIT,
00228    OPT_ARG_MUSICBACK,
00229    OPT_ARG_CALLEE_MACRO,
00230    OPT_ARG_PRIVACY,
00231    OPT_ARG_DURATION_STOP,
00232    /* note: this entry _MUST_ be the last one in the enum */
00233    OPT_ARG_ARRAY_SIZE,
00234 } dial_exec_option_args;


Function Documentation

AST_APP_OPTIONS ( dial_exec_options   ) 

char* description ( void   ) 

Provides a description of the module.

Returns:
a short description of your module

Definition at line 1794 of file app_dial.c.

01795 {
01796    return tdesc;
01797 }

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

Definition at line 1659 of file app_dial.c.

References dial_exec_full().

Referenced by load_module().

01660 {
01661    struct ast_flags peerflags;
01662    memset(&peerflags, 0, sizeof(peerflags));
01663    return dial_exec_full(chan, data, &peerflags);
01664 }

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

Definition at line 745 of file app_dial.c.

References ast_channel::_softhangup, ast_channel::_state, ast_channel::accountcode, ast_channel::adsicpe, app, AST_APP_ARG, ast_app_group_set_channel(), ast_app_parse_options(), ast_autoservice_start(), ast_autoservice_stop(), ast_bridge_call(), ast_call(), ast_cause2str(), AST_CAUSE_CONGESTION, ast_cdr_reset(), ast_cdr_setdestchan(), ast_channel_inherit_variables(), ast_channel_make_compatible(), ast_channel_sendurl(), ast_channel_supports_html(), ast_config_AST_VAR_DIR, AST_CONTROL_RINGING, ast_copy_flags, ast_deactivate_generator(), AST_DECLARE_APP_ARGS, AST_DIGIT_ANY, ast_dtmf_stream(), AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PLAY_WARNING, AST_FEATURE_REDIRECT, ast_filedelete(), ast_fileexists(), ast_goto_if_exists(), ast_hangup(), ast_indicate(), ast_log(), AST_MAX_EXTENSION, AST_MAX_FORWARDS, ast_moh_start(), ast_moh_stop(), ast_parseable_goto(), AST_PBX_KEEPALIVE, AST_PBX_NO_HANGUP_PEER, ast_pbx_start(), ast_play_and_record(), ast_play_and_wait(), AST_PRIVACY_ALLOW, ast_privacy_check(), AST_PRIVACY_DENY, AST_PRIVACY_KILL, ast_privacy_set(), AST_PRIVACY_TORTURE, AST_PRIVACY_UNKNOWN, ast_request(), ast_senddigit(), ast_set2_flag, ast_set_callerid(), ast_set_flag, ast_shrink_phone_number(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_true(), ast_verbose(), ast_waitstream(), ast_channel::cdr, ast_channel::cdrflags, localuser::chan, ast_channel::cid, ast_callerid::cid_ani, 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, DIAL_NOFORWARDHTML, DIAL_STILLGOING, ast_bridge_config::end_sound, ast_channel::exten, ast_flags::flags, free, get_cid_name(), HANDLE_CAUSE, ast_channel::hangupcause, hanguptree(), ast_channel::language, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_DEBUG, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_channel::macroexten, malloc, moh, ast_channel::musicclass, ast_channel::name, ast_channel::nativeformats, OPT_ANNOUNCE, OPT_ARG_ANNOUNCE, OPT_ARG_ARRAY_SIZE, OPT_ARG_CALLEE_MACRO, OPT_ARG_DURATION_LIMIT, OPT_ARG_DURATION_STOP, OPT_ARG_GOTO, OPT_ARG_MUSICBACK, OPT_ARG_PRIVACY, OPT_ARG_SENDDTMF, OPT_CALLEE_HANGUP, OPT_CALLEE_MACRO, OPT_CALLEE_MONITOR, OPT_CALLEE_TRANSFER, OPT_CALLER_HANGUP, OPT_CALLER_MONITOR, OPT_CALLER_TRANSFER, OPT_DTMF_EXIT, OPT_DURATION_LIMIT, OPT_DURATION_STOP, OPT_FORCECLID, OPT_GO_ON, OPT_GOTO, OPT_MUSICBACK, OPT_ORIGINAL_CLID, OPT_PRIORITY_JUMP, OPT_PRIVACY, OPT_RESETCDR, OPT_RINGBACK, OPT_SCREEN_NOCLID, OPT_SCREEN_NOINTRO, OPT_SCREENING, OPT_SENDDTMF, option_debug, option_priority_jumping, option_verbose, parse(), pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), peers, ast_bridge_config::play_warning, ast_channel::priority, result, senddialevent(), ast_bridge_config::start_sound, ast_bridge_config::start_time, strdup, strsep(), ast_bridge_config::timelimit, ast_channel::transfercapability, var, VERBOSE_PREFIX_3, wait_for_answer(), ast_bridge_config::warning_freq, ast_bridge_config::warning_sound, and ast_channel::whentohangup.

Referenced by dial_exec(), and retrydial_exec().

00746 {
00747    int res=-1;
00748    struct localuser *u;
00749    char *tech, *number, *rest, *cur;
00750    char privcid[256];
00751    char privintro[1024];
00752    struct localuser *outgoing=NULL, *tmp;
00753    struct ast_channel *peer;
00754    int to;
00755    int numbusy = 0;
00756    int numcongestion = 0;
00757    int numnochan = 0;
00758    int cause;
00759    char numsubst[AST_MAX_EXTENSION];
00760    char restofit[AST_MAX_EXTENSION];
00761    char cidname[AST_MAX_EXTENSION];
00762    char toast[80];
00763    char *newnum;
00764    char *l;
00765    int privdb_val=0;
00766    unsigned int calldurationlimit=0;
00767    struct ast_bridge_config config;
00768    long timelimit = 0;
00769    long play_warning = 0;
00770    long warning_freq=0;
00771    char *warning_sound=NULL;
00772    char *end_sound=NULL;
00773    char *start_sound=NULL;
00774    char *dtmfcalled=NULL, *dtmfcalling=NULL;
00775    char *var;
00776    char status[256];
00777    int play_to_caller=0,play_to_callee=0;
00778    int sentringing=0, moh=0;
00779    char *outbound_group = NULL;
00780    char *macro_result = NULL, *macro_transfer_dest = NULL;
00781    int digit = 0, result = 0;
00782    time_t start_time, answer_time, end_time;
00783    struct ast_app *app = NULL;
00784 
00785    char *parse;
00786    AST_DECLARE_APP_ARGS(args,
00787               AST_APP_ARG(peers);
00788               AST_APP_ARG(timeout);
00789               AST_APP_ARG(options);
00790               AST_APP_ARG(url);
00791    );
00792    struct ast_flags opts = { 0, };
00793    char *opt_args[OPT_ARG_ARRAY_SIZE];
00794 
00795    if (ast_strlen_zero(data)) {
00796       ast_log(LOG_WARNING, "Dial requires an argument (technology/number)\n");
00797       return -1;
00798    }
00799 
00800    LOCAL_USER_ADD(u);
00801 
00802    if (!(parse = ast_strdupa(data))) {
00803       ast_log(LOG_WARNING, "Memory allocation failure\n");
00804       LOCAL_USER_REMOVE(u);
00805       return -1;
00806    }
00807    
00808    AST_STANDARD_APP_ARGS(args, parse);
00809 
00810    if (!ast_strlen_zero(args.options)) {
00811       if (ast_app_parse_options(dial_exec_options, &opts, opt_args, args.options)) {
00812          LOCAL_USER_REMOVE(u);
00813          return -1;
00814       }
00815    }
00816 
00817    if (ast_strlen_zero(args.peers)) {
00818       ast_log(LOG_WARNING, "Dial requires an argument (technology/number)\n");
00819       LOCAL_USER_REMOVE(u);
00820       return -1;
00821    }
00822 
00823    if (ast_test_flag(&opts, OPT_DURATION_STOP) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_STOP])) {
00824       calldurationlimit = atoi(opt_args[OPT_ARG_DURATION_STOP]);
00825       if (option_verbose > 2)
00826          ast_verbose(VERBOSE_PREFIX_3 "Setting call duration limit to %d seconds.\n",calldurationlimit);       
00827    }
00828 
00829    if (ast_test_flag(&opts, OPT_SENDDTMF) && !ast_strlen_zero(opt_args[OPT_ARG_SENDDTMF])) {
00830       parse = opt_args[OPT_ARG_SENDDTMF];
00831       dtmfcalled = strsep(&parse, ":");
00832       dtmfcalling = parse;
00833    }
00834 
00835    if (ast_test_flag(&opts, OPT_DURATION_LIMIT) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])) {
00836       char *limit_str, *warning_str, *warnfreq_str;
00837 
00838       parse = opt_args[OPT_ARG_DURATION_LIMIT];
00839       limit_str = strsep(&parse, ":");
00840       warning_str = strsep(&parse, ":");
00841       warnfreq_str = parse;
00842 
00843       timelimit = atol(limit_str);
00844       if (warning_str)
00845          play_warning = atol(warning_str);
00846       if (warnfreq_str)
00847          warning_freq = atol(warnfreq_str);
00848 
00849       if (!timelimit) {
00850          timelimit = play_to_caller = play_to_callee = play_warning = warning_freq = 0;
00851          warning_sound = NULL;
00852       } else if (play_warning > timelimit) {
00853          /* If the first warning is requested _after_ the entire call would end,
00854             and no warning frequency is requested, then turn off the warning. If
00855             a warning frequency is requested, reduce the 'first warning' time by
00856             that frequency until it falls within the call's total time limit.
00857          */
00858 
00859          if (!warning_freq) {
00860             play_warning = 0;
00861          } else {
00862             while (play_warning > timelimit)
00863                play_warning -= warning_freq;
00864             if (play_warning < 1)
00865                play_warning = warning_freq = 0;
00866          }
00867       }
00868 
00869       var = pbx_builtin_getvar_helper(chan,"LIMIT_PLAYAUDIO_CALLER");
00870       play_to_caller = var ? ast_true(var) : 1;
00871       
00872       var = pbx_builtin_getvar_helper(chan,"LIMIT_PLAYAUDIO_CALLEE");
00873       play_to_callee = var ? ast_true(var) : 0;
00874       
00875       if (!play_to_caller && !play_to_callee)
00876          play_to_caller=1;
00877       
00878       var = pbx_builtin_getvar_helper(chan,"LIMIT_WARNING_FILE");
00879       warning_sound = var ? var : "timeleft";
00880       
00881       var = pbx_builtin_getvar_helper(chan,"LIMIT_TIMEOUT_FILE");
00882       end_sound = var ? var : NULL;
00883       
00884       var = pbx_builtin_getvar_helper(chan,"LIMIT_CONNECT_FILE");
00885       start_sound = var ? var : NULL;
00886 
00887       /* undo effect of S(x) in case they are both used */
00888       calldurationlimit = 0; 
00889       /* more efficient do it like S(x) does since no advanced opts*/
00890       if (!play_warning && !start_sound && !end_sound && timelimit) { 
00891          calldurationlimit = timelimit/1000;
00892          timelimit = play_to_caller = play_to_callee = play_warning = warning_freq = 0;
00893       } else if (option_verbose > 2) {
00894          ast_verbose(VERBOSE_PREFIX_3 "Limit Data for this call:\n");
00895          ast_verbose(VERBOSE_PREFIX_3 "- timelimit     = %ld\n", timelimit);
00896          ast_verbose(VERBOSE_PREFIX_3 "- play_warning  = %ld\n", play_warning);
00897          ast_verbose(VERBOSE_PREFIX_3 "- play_to_caller= %s\n", play_to_caller ? "yes" : "no");
00898          ast_verbose(VERBOSE_PREFIX_3 "- play_to_callee= %s\n", play_to_callee ? "yes" : "no");
00899          ast_verbose(VERBOSE_PREFIX_3 "- warning_freq  = %ld\n", warning_freq);
00900          ast_verbose(VERBOSE_PREFIX_3 "- start_sound   = %s\n", start_sound ? start_sound : "UNDEF");
00901          ast_verbose(VERBOSE_PREFIX_3 "- warning_sound = %s\n", warning_sound ? warning_sound : "UNDEF");
00902          ast_verbose(VERBOSE_PREFIX_3 "- end_sound     = %s\n", end_sound ? end_sound : "UNDEF");
00903       }
00904    }
00905 
00906    if (ast_test_flag(&opts, OPT_RESETCDR) && chan->cdr)
00907       ast_cdr_reset(chan->cdr, NULL);
00908    if (ast_test_flag(&opts, OPT_PRIVACY) && ast_strlen_zero(opt_args[OPT_ARG_PRIVACY]))
00909       opt_args[OPT_ARG_PRIVACY] = ast_strdupa(chan->exten);
00910    if (ast_test_flag(&opts, OPT_PRIVACY) || ast_test_flag(&opts, OPT_SCREENING)) {
00911       char callerid[60];
00912 
00913       l = chan->cid.cid_num;
00914       if (!ast_strlen_zero(l)) {
00915          ast_shrink_phone_number(l);
00916          if( ast_test_flag(&opts, OPT_PRIVACY) ) {
00917             if (option_verbose > 2)
00918                ast_verbose( VERBOSE_PREFIX_3  "Privacy DB is '%s', clid is '%s'\n",
00919                        opt_args[OPT_ARG_PRIVACY], l);
00920             privdb_val = ast_privacy_check(opt_args[OPT_ARG_PRIVACY], l);
00921          }
00922          else {
00923             if (option_verbose > 2)
00924                ast_verbose( VERBOSE_PREFIX_3  "Privacy Screening, clid is '%s'\n", l);
00925             privdb_val = AST_PRIVACY_UNKNOWN;
00926          }
00927       } else {
00928          char *tnam, *tn2;
00929 
00930          tnam = ast_strdupa(chan->name);
00931          /* clean the channel name so slashes don't try to end up in disk file name */
00932          for(tn2 = tnam; *tn2; tn2++) {
00933             if( *tn2=='/')
00934                *tn2 = '=';  /* any other chars to be afraid of? */
00935          }
00936          if (option_verbose > 2)
00937             ast_verbose( VERBOSE_PREFIX_3  "Privacy-- callerid is empty\n");
00938 
00939          snprintf(callerid, sizeof(callerid), "NOCALLERID_%s%s", chan->exten, tnam);
00940          l = callerid;
00941          privdb_val = AST_PRIVACY_UNKNOWN;
00942       }
00943       
00944       ast_copy_string(privcid,l,sizeof(privcid));
00945 
00946       if( strncmp(privcid,"NOCALLERID",10) != 0 && ast_test_flag(&opts, OPT_SCREEN_NOCLID) ) { /* if callerid is set, and ast_test_flag(&opts, OPT_SCREEN_NOCLID) is set also */  
00947          if (option_verbose > 2)
00948             ast_verbose( VERBOSE_PREFIX_3  "CallerID set (%s); N option set; Screening should be off\n", privcid);
00949          privdb_val = AST_PRIVACY_ALLOW;
00950       }
00951       else if( ast_test_flag(&opts, OPT_SCREEN_NOCLID) && strncmp(privcid,"NOCALLERID",10) == 0 ) {
00952          if (option_verbose > 2)
00953             ast_verbose( VERBOSE_PREFIX_3  "CallerID blank; N option set; Screening should happen; dbval is %d\n", privdb_val);
00954       }
00955       
00956       if( privdb_val == AST_PRIVACY_DENY ) {
00957          strcpy(status, "NOANSWER");
00958          ast_verbose( VERBOSE_PREFIX_3  "Privacy DB reports PRIVACY_DENY for this callerid. Dial reports unavailable\n");
00959          res=0;
00960          goto out;
00961       }
00962       else if( privdb_val == AST_PRIVACY_KILL ) {
00963          strcpy(status, "DONTCALL");
00964          if (option_priority_jumping || ast_test_flag(&opts, OPT_PRIORITY_JUMP)) {
00965             ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 201);
00966          }
00967          res = 0;
00968          goto out; /* Is this right? */
00969       }
00970       else if( privdb_val == AST_PRIVACY_TORTURE ) {
00971          strcpy(status, "TORTURE");
00972          if (option_priority_jumping || ast_test_flag(&opts, OPT_PRIORITY_JUMP)) {
00973             ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 301);
00974          }
00975          res = 0;
00976          goto out; /* is this right??? */
00977       }
00978       else if( privdb_val == AST_PRIVACY_UNKNOWN ) {
00979          /* Get the user's intro, store it in priv-callerintros/$CID, 
00980             unless it is already there-- this should be done before the 
00981             call is actually dialed  */
00982 
00983          /* make sure the priv-callerintros dir actually exists */
00984          snprintf(privintro, sizeof(privintro), "%s/sounds/priv-callerintros", ast_config_AST_VAR_DIR);
00985          if (mkdir(privintro, 0755) && errno != EEXIST) {
00986             ast_log(LOG_WARNING, "privacy: can't create directory priv-callerintros: %s\n", strerror(errno));
00987             res = -1;
00988             goto out;
00989          }
00990 
00991          snprintf(privintro,sizeof(privintro),"priv-callerintros/%s", privcid);
00992          if( ast_fileexists(privintro,NULL,NULL ) > 0 && strncmp(privcid,"NOCALLERID",10) != 0) {
00993             /* the DELUX version of this code would allow this caller the
00994                option to hear and retape their previously recorded intro.
00995             */
00996          }
00997          else {
00998             int duration; /* for feedback from play_and_wait */
00999             /* the file doesn't exist yet. Let the caller submit his
01000                vocal intro for posterity */
01001             /* priv-recordintro script:
01002 
01003                "At the tone, please say your name:"
01004 
01005             */
01006             res = ast_play_and_record(chan, "priv-recordintro", privintro, 4, "gsm", &duration, 128, 2000, 0);  /* NOTE: I've reduced the total time to */
01007                                              /* 4 sec don't think we'll need a lock removed, we 
01008                                                 took care of conflicts by naming the privintro file */
01009             if (res == -1) {
01010                /* Delete the file regardless since they hung up during recording */
01011                                         ast_filedelete(privintro, NULL);
01012                                         if( ast_fileexists(privintro,NULL,NULL ) > 0 )
01013                                                 ast_log(LOG_NOTICE,"privacy: ast_filedelete didn't do its job on %s\n", privintro);
01014                                         else if (option_verbose > 2)
01015                                                 ast_verbose( VERBOSE_PREFIX_3 "Successfully deleted %s intro file\n", privintro);
01016                goto out;
01017             }
01018          }
01019       }
01020    }
01021 
01022    /* If a channel group has been specified, get it for use when we create peer channels */
01023    outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP");
01024 
01025    ast_copy_flags(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID | OPT_CALLER_HANGUP);
01026    cur = args.peers;
01027    do {
01028       /* Remember where to start next time */
01029       rest = strchr(cur, '&');
01030       if (rest) {
01031          *rest = 0;
01032          rest++;
01033       }
01034       /* Get a technology/[device:]number pair */
01035       tech = cur;
01036       number = strchr(tech, '/');
01037       if (!number) {
01038          ast_log(LOG_WARNING, "Dial argument takes format (technology/[device:]number1)\n");
01039          goto out;
01040       }
01041       *number = '\0';
01042       number++;
01043       tmp = malloc(sizeof(struct localuser));
01044       if (!tmp) {
01045          ast_log(LOG_WARNING, "Out of memory\n");
01046          goto out;
01047       }
01048       memset(tmp, 0, sizeof(struct localuser));
01049       if (opts.flags) {
01050          ast_copy_flags(tmp, &opts,
01051                    OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
01052                    OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
01053                    OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
01054                    OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID);
01055          ast_set2_flag(tmp, args.url, DIAL_NOFORWARDHTML);  
01056       }
01057       ast_copy_string(numsubst, number, sizeof(numsubst));
01058       /* If we're dialing by extension, look at the extension to know what to dial */
01059       if ((newnum = strstr(numsubst, "BYEXTENSION"))) {
01060          /* strlen("BYEXTENSION") == 11 */
01061          ast_copy_string(restofit, newnum + 11, sizeof(restofit));
01062          snprintf(newnum, sizeof(numsubst) - (newnum - numsubst), "%s%s", chan->exten,restofit);
01063          if (option_debug)
01064             ast_log(LOG_DEBUG, "Dialing by extension %s\n", numsubst);
01065       }
01066       /* Request the peer */
01067       tmp->chan = ast_request(tech, chan->nativeformats, numsubst, &cause);
01068       if (!tmp->chan) {
01069          /* If we can't, just go on to the next call */
01070          ast_log(LOG_NOTICE, "Unable to create channel of type '%s' (cause %d - %s)\n", tech, cause, ast_cause2str(cause));
01071          HANDLE_CAUSE(cause, chan);
01072          cur = rest;
01073          if (!cur)
01074             chan->hangupcause = cause;
01075          continue;
01076       }
01077       pbx_builtin_setvar_helper(tmp->chan, "DIALEDPEERNUMBER", numsubst);
01078       if (!ast_strlen_zero(tmp->chan->call_forward)) {
01079          char tmpchan[256];
01080          char *stuff;
01081          char *tech;
01082          ast_copy_string(tmpchan, tmp->chan->call_forward, sizeof(tmpchan));
01083          if ((stuff = strchr(tmpchan, '/'))) {
01084             *stuff = '\0';
01085             stuff++;
01086             tech = tmpchan;
01087          } else {
01088             snprintf(tmpchan, sizeof(tmpchan), "%s@%s", tmp->chan->call_forward, tmp->chan->context);
01089             stuff = tmpchan;
01090             tech = "Local";
01091          }
01092          tmp->forwards++;
01093          if (tmp->forwards < AST_MAX_FORWARDS) {
01094             if (option_verbose > 2)
01095                ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", chan->name, tech, stuff, tmp->chan->name);
01096             ast_hangup(tmp->chan);
01097             /* Setup parameters */
01098             tmp->chan = ast_request(tech, chan->nativeformats, stuff, &cause);
01099             if (!tmp->chan)
01100                ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
01101             else
01102                ast_channel_inherit_variables(chan, tmp->chan);
01103          } else {
01104             if (option_verbose > 2)
01105                ast_verbose(VERBOSE_PREFIX_3 "Too many forwards from %s\n", tmp->chan->name);
01106             ast_hangup(tmp->chan);
01107             tmp->chan = NULL;
01108             cause = AST_CAUSE_CONGESTION;
01109          }
01110          if (!tmp->chan) {
01111             HANDLE_CAUSE(cause, chan);
01112             cur = rest;
01113             continue;
01114          }
01115       }
01116 
01117       /* Inherit specially named variables from parent channel */
01118       ast_channel_inherit_variables(chan, tmp->chan);
01119 
01120       tmp->chan->appl = "AppDial";
01121       tmp->chan->data = "(Outgoing Line)";
01122       tmp->chan->whentohangup = 0;
01123       if (tmp->chan->cid.cid_num)
01124          free(tmp->chan->cid.cid_num);
01125       tmp->chan->cid.cid_num = NULL;
01126       if (tmp->chan->cid.cid_name)
01127          free(tmp->chan->cid.cid_name);
01128       tmp->chan->cid.cid_name = NULL;
01129       if (tmp->chan->cid.cid_ani)
01130          free(tmp->chan->cid.cid_ani);
01131       tmp->chan->cid.cid_ani = NULL;
01132 
01133       if (chan->cid.cid_num) 
01134          tmp->chan->cid.cid_num = strdup(chan->cid.cid_num);
01135       if (chan->cid.cid_name) 
01136          tmp->chan->cid.cid_name = strdup(chan->cid.cid_name);
01137       if (chan->cid.cid_ani) 
01138          tmp->chan->cid.cid_ani = strdup(chan->cid.cid_ani);
01139       
01140       /* Copy language from incoming to outgoing */
01141       ast_copy_string(tmp->chan->language, chan->language, sizeof(tmp->chan->language));
01142       ast_copy_string(tmp->chan->accountcode, chan->accountcode, sizeof(tmp->chan->accountcode));
01143       tmp->chan->cdrflags = chan->cdrflags;
01144       if (ast_strlen_zero(tmp->chan->musicclass))
01145          ast_copy_string(tmp->chan->musicclass, chan->musicclass, sizeof(tmp->chan->musicclass));
01146       if (chan->cid.cid_rdnis)
01147          tmp->chan->cid.cid_rdnis = strdup(chan->cid.cid_rdnis);
01148       /* Pass callingpres setting */
01149       tmp->chan->cid.cid_pres = chan->cid.cid_pres;
01150       /* Pass type of number */
01151       tmp->chan->cid.cid_ton = chan->cid.cid_ton;
01152       /* Pass type of tns */
01153       tmp->chan->cid.cid_tns = chan->cid.cid_tns;
01154       /* Presense of ADSI CPE on outgoing channel follows ours */
01155       tmp->chan->adsicpe = chan->adsicpe;
01156       /* Pass the transfer capability */
01157       tmp->chan->transfercapability = chan->transfercapability;
01158 
01159       /* If we have an outbound group, set this peer channel to it */
01160       if (outbound_group)
01161          ast_app_group_set_channel(tmp->chan, outbound_group);
01162 
01163       /* Place the call, but don't wait on the answer */
01164       res = ast_call(tmp->chan, numsubst, 0);
01165 
01166       /* Save the info in cdr's that we called them */
01167       if (chan->cdr)
01168          ast_cdr_setdestchan(chan->cdr, tmp->chan->name);
01169 
01170       /* check the results of ast_call */
01171       if (res) {
01172          /* Again, keep going even if there's an error */
01173          if (option_debug)
01174             ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
01175          else if (option_verbose > 2)
01176             ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", numsubst);
01177          ast_hangup(tmp->chan);
01178          tmp->chan = NULL;
01179          cur = rest;
01180          continue;
01181       } else {
01182          senddialevent(chan, tmp->chan);
01183          if (option_verbose > 2)
01184             ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", numsubst);
01185          if (!ast_test_flag(peerflags, OPT_ORIGINAL_CLID))
01186             ast_set_callerid(tmp->chan, ast_strlen_zero(chan->macroexten) ? chan->exten : chan->macroexten, get_cid_name(cidname, sizeof(cidname), chan), NULL);
01187       }
01188       /* Put them in the list of outgoing thingies...  We're ready now. 
01189          XXX If we're forcibly removed, these outgoing calls won't get
01190          hung up XXX */
01191       ast_set_flag(tmp, DIAL_STILLGOING); 
01192       tmp->next = outgoing;
01193       outgoing = tmp;
01194       /* If this line is up, don't try anybody else */
01195       if (outgoing->chan->_state == AST_STATE_UP)
01196          break;
01197       cur = rest;
01198    } while (cur);
01199    
01200    if (!ast_strlen_zero(args.timeout)) {
01201       to = atoi(args.timeout);
01202       if (to > 0)
01203          to *= 1000;
01204       else
01205          ast_log(LOG_WARNING, "Invalid timeout specified: '%s'\n", args.timeout);
01206    } else
01207       to = -1;
01208 
01209    if (outgoing) {
01210       /* Our status will at least be NOANSWER */
01211       strcpy(status, "NOANSWER");
01212       if (ast_test_flag(outgoing, OPT_MUSICBACK)) {
01213          moh=1;
01214          ast_moh_start(chan, opt_args[OPT_ARG_MUSICBACK]);
01215       } else if (ast_test_flag(outgoing, OPT_RINGBACK)) {
01216          ast_indicate(chan, AST_CONTROL_RINGING);
01217          sentringing++;
01218       }
01219    } else
01220       strcpy(status, "CHANUNAVAIL");
01221 
01222    time(&start_time);
01223    peer = wait_for_answer(chan, outgoing, &to, peerflags, &sentringing, status, sizeof(status), numbusy, numnochan, numcongestion, ast_test_flag(&opts, OPT_PRIORITY_JUMP), &result);
01224    
01225    if (!peer) {
01226       if (result) {
01227          res = result;
01228       } else if (to) 
01229          /* Musta gotten hung up */
01230          res = -1;
01231       else 
01232          /* Nobody answered, next please? */
01233          res = 0;
01234       
01235       goto out;
01236    }
01237    if (peer) {
01238       time(&answer_time);
01239 #ifdef OSP_SUPPORT
01240       /* Once call is answered, ditch the OSP Handle */
01241       pbx_builtin_setvar_helper(chan, "_OSPHANDLE", "");
01242 #endif
01243       strcpy(status, "ANSWER");
01244       /* Ah ha!  Someone answered within the desired timeframe.  Of course after this
01245          we will always return with -1 so that it is hung up properly after the 
01246          conversation.  */
01247       hanguptree(outgoing, peer);
01248       outgoing = NULL;
01249       /* If appropriate, log that we have a destination channel */
01250       if (chan->cdr)
01251          ast_cdr_setdestchan(chan->cdr, peer->name);
01252       if (peer->name)
01253          pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", peer->name);
01254 
01255       number = pbx_builtin_getvar_helper(peer, "DIALEDPEERNUMBER");
01256       if (!number)
01257          number = numsubst;
01258       pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", number);
01259       if (!ast_strlen_zero(args.url) && ast_channel_supports_html(peer) ) {
01260          ast_log(LOG_DEBUG, "app_dial: sendurl=%s.\n", args.url);
01261          ast_channel_sendurl( peer, args.url );
01262       }
01263       if (ast_test_flag(&opts, OPT_PRIVACY) || ast_test_flag(&opts, OPT_SCREENING)) {
01264          int res2;
01265          int loopcount = 0;
01266          if( privdb_val == AST_PRIVACY_UNKNOWN ) {
01267 
01268             /* Get the user's intro, store it in priv-callerintros/$CID, 
01269                unless it is already there-- this should be done before the 
01270                call is actually dialed  */
01271 
01272             /* all ring indications and moh for the caller has been halted as soon as the 
01273                target extension was picked up. We are going to have to kill some
01274                time and make the caller believe the peer hasn't picked up yet */
01275 
01276             if (ast_test_flag(&opts, OPT_MUSICBACK) && !ast_strlen_zero(opt_args[OPT_ARG_MUSICBACK])) {
01277                ast_indicate(chan, -1);
01278                ast_moh_start(chan, opt_args[OPT_ARG_MUSICBACK]);
01279             } else if (ast_test_flag(&opts, OPT_RINGBACK)) {
01280                ast_indicate(chan, AST_CONTROL_RINGING);
01281                sentringing++;
01282             }
01283 
01284             /* Start autoservice on the other chan ?? */
01285             res2 = ast_autoservice_start(chan);
01286             /* Now Stream the File */
01287             if (!res2) {
01288                do {
01289                   if (!res2)
01290                      res2 = ast_play_and_wait(peer,"priv-callpending");
01291                   if ( res2 < '1' || (ast_test_flag(&opts, OPT_PRIVACY) && res2>'5') || (ast_test_flag(&opts, OPT_SCREENING) && res2 > '4') ) /* uh, interrupting with a bad answer is ... ignorable! */
01292                      res2 = 0;
01293                   
01294                   /* priv-callpending script: 
01295                      "I have a caller waiting, who introduces themselves as:"
01296                   */
01297                   if (!res2)
01298                      res2 = ast_play_and_wait(peer, privintro);
01299                   if ( res2 < '1' || (ast_test_flag(&opts, OPT_PRIVACY) && res2>'5') || (ast_test_flag(&opts, OPT_SCREENING) && res2 > '4') ) /* uh, interrupting with a bad answer is ... ignorable! */
01300                      res2 = 0;
01301                   /* now get input from the called party, as to their choice */
01302                   if (!res2) {
01303                      if( ast_test_flag(&opts, OPT_PRIVACY) )
01304                         res2 = ast_play_and_wait(peer,"priv-callee-options");
01305                      if( ast_test_flag(&opts, OPT_SCREENING) )
01306                         res2 = ast_play_and_wait(peer,"screen-callee-options");
01307                   }
01308                   /* priv-callee-options script:
01309                      "Dial 1 if you wish this caller to reach you directly in the future,
01310                         and immediately connect to their incoming call
01311                       Dial 2 if you wish to send this caller to voicemail now and 
01312                         forevermore.
01313                       Dial 3 to send this callerr to the torture menus, now and forevermore.
01314                       Dial 4 to send this caller to a simple "go away" menu, now and forevermore.
01315                       Dial 5 to allow this caller to come straight thru to you in the future,
01316                   but right now, just this once, send them to voicemail."
01317                   */
01318             
01319                   /* screen-callee-options script:
01320                      "Dial 1 if you wish to immediately connect to the incoming call
01321                       Dial 2 if you wish to send this caller to voicemail.
01322                       Dial 3 to send this callerr to the torture menus.
01323                       Dial 4 to send this caller to a simple "go away" menu.
01324                   */
01325                   if( !res2 || res2 < '1' || (ast_test_flag(&opts, OPT_PRIVACY) && res2 > '5') || (ast_test_flag(&opts, OPT_SCREENING) && res2 > '4') ) {
01326                      /* invalid option */
01327                      res2 = ast_play_and_wait(peer,"vm-sorry");
01328                   }
01329                   loopcount++; /* give the callee a couple chances to make a choice */
01330                } while( (!res2 || res2 < '1' || (ast_test_flag(&opts, OPT_PRIVACY) && res2 > '5') || (ast_test_flag(&opts, OPT_SCREENING) && res2 > '4')) && loopcount < 2 );
01331             }
01332 
01333             switch(res2) {
01334             case '1':
01335                if( ast_test_flag(&opts, OPT_PRIVACY) ) {
01336                   if (option_verbose > 2)
01337                      ast_verbose( VERBOSE_PREFIX_3 "--Set privacy database entry %s/%s to ALLOW\n",
01338                              opt_args[OPT_ARG_PRIVACY], privcid);
01339                   ast_privacy_set(opt_args[OPT_ARG_PRIVACY], privcid, AST_PRIVACY_ALLOW);
01340                }
01341                break;
01342             case '2':
01343                if( ast_test_flag(&opts, OPT_PRIVACY) ) {
01344                   if (option_verbose > 2)
01345                      ast_verbose( VERBOSE_PREFIX_3 "--Set privacy database entry %s/%s to DENY\n",
01346                              opt_args[OPT_ARG_PRIVACY], privcid);
01347                   ast_privacy_set(opt_args[OPT_ARG_PRIVACY], privcid, AST_PRIVACY_DENY);
01348                }
01349                strcpy(status,"NOANSWER");
01350                if (ast_test_flag(&opts, OPT_MUSICBACK)) {
01351                   ast_moh_stop(chan);
01352                } else if (ast_test_flag(&opts, OPT_RINGBACK)) {
01353                   ast_indicate(chan, -1);
01354                   sentringing=0;
01355                }
01356                res2 = ast_autoservice_stop(chan);
01357                ast_hangup(peer); /* hang up on the callee -- he didn't want to talk anyway! */
01358                res=0;
01359                goto out;
01360             case '3':
01361                if( ast_test_flag(&opts, OPT_PRIVACY) ) {
01362                   if (option_verbose > 2)
01363                      ast_verbose( VERBOSE_PREFIX_3 "--Set privacy database entry %s/%s to TORTURE\n",
01364                              opt_args[OPT_ARG_PRIVACY], privcid);
01365                   ast_privacy_set(opt_args[OPT_ARG_PRIVACY], privcid, AST_PRIVACY_TORTURE);
01366                }
01367                ast_copy_string(status, "TORTURE", sizeof(status));
01368                
01369                res = 0;
01370                if (ast_test_flag(&opts, OPT_MUSICBACK)) {
01371                   ast_moh_stop(chan);
01372                } else if (ast_test_flag(&opts, OPT_RINGBACK)) {
01373                   ast_indicate(chan, -1);
01374                   sentringing=0;
01375                }
01376                res2 = ast_autoservice_stop(chan);
01377                ast_hangup(peer); /* hang up on the caller -- he didn't want to talk anyway! */
01378                goto out; /* Is this right? */
01379             case '4':
01380                if( ast_test_flag(&opts, OPT_PRIVACY) ) {
01381                   if (option_verbose > 2)
01382                      ast_verbose( VERBOSE_PREFIX_3 "--Set privacy database entry %s/%s to KILL\n",
01383                              opt_args[OPT_ARG_PRIVACY], privcid);
01384                   ast_privacy_set(opt_args[OPT_ARG_PRIVACY], privcid, AST_PRIVACY_KILL);
01385                }
01386 
01387                ast_copy_string(status, "DONTCALL", sizeof(status));
01388                res = 0;
01389                if (ast_test_flag(&opts, OPT_MUSICBACK)) {
01390                   ast_moh_stop(chan);
01391                } else if (ast_test_flag(&opts, OPT_RINGBACK)) {
01392                   ast_indicate(chan, -1);
01393                   sentringing=0;
01394                }
01395                res2 = ast_autoservice_stop(chan);
01396                ast_hangup(peer); /* hang up on the caller -- he didn't want to talk anyway! */
01397                goto out; /* Is this right? */
01398             case '5':
01399                if( ast_test_flag(&opts, OPT_PRIVACY) ) {
01400                   if (option_verbose > 2)
01401                      ast_verbose( VERBOSE_PREFIX_3 "--Set privacy database entry %s/%s to ALLOW\n",
01402                              opt_args[OPT_ARG_PRIVACY], privcid);
01403                   ast_privacy_set(opt_args[OPT_ARG_PRIVACY], privcid, AST_PRIVACY_ALLOW);
01404                   if (ast_test_flag(&opts, OPT_MUSICBACK)) {
01405                      ast_moh_stop(chan);
01406                   } else if (ast_test_flag(&opts, OPT_RINGBACK)) {
01407                      ast_indicate(chan, -1);
01408                      sentringing=0;
01409                   }
01410                   res2 = ast_autoservice_stop(chan);
01411                   ast_hangup(peer); /* hang up on the caller -- he didn't want to talk anyway! */
01412                   res=0;
01413                   goto out;
01414                } /* if not privacy, then 5 is the same as "default" case */
01415             default:
01416                /* well, if the user messes up, ... he had his chance... What Is The Best Thing To Do?  */
01417                /* well, there seems basically two choices. Just patch the caller thru immediately,
01418                               or,... put 'em thru to voicemail. */
01419                /* since the callee may have hung up, let's do the voicemail thing, no database decision */
01420                if (option_verbose > 2)
01421                   ast_log(LOG_NOTICE,"privacy: no valid response from the callee. Sending the caller to voicemail, the callee isn't responding\n");
01422                if (ast_test_flag(&opts, OPT_MUSICBACK)) {
01423                   ast_moh_stop(chan);
01424                } else if (ast_test_flag(&opts, OPT_RINGBACK)) {
01425                   ast_indicate(chan, -1);
01426                   sentringing=0;
01427                }
01428                res2 = ast_autoservice_stop(chan);
01429                ast_hangup(peer); /* hang up on the callee -- he didn't want to talk anyway! */
01430                res=0;
01431                goto out;
01432             }
01433             if (ast_test_flag(&opts, OPT_MUSICBACK)) {
01434                ast_moh_stop(chan);
01435             } else if (ast_test_flag(&opts, OPT_RINGBACK)) {
01436                ast_indicate(chan, -1);
01437                sentringing=0;
01438             }
01439             res2 = ast_autoservice_stop(chan);
01440             /* if the intro is NOCALLERID, then there's no reason to leave it on disk, it'll 
01441                just clog things up, and it's not useful information, not being tied to a CID */
01442             if( strncmp(privcid,"NOCALLERID",10) == 0 || ast_test_flag(&opts, OPT_SCREEN_NOINTRO) ) {
01443                ast_filedelete(privintro, NULL);
01444                if( ast_fileexists(privintro,NULL,NULL ) > 0 )
01445                   ast_log(LOG_NOTICE,"privacy: ast_filedelete didn't do its job on %s\n", privintro);
01446                else if (option_verbose > 2)
01447                   ast_verbose( VERBOSE_PREFIX_3 "Successfully deleted %s intro file\n", privintro);
01448             }
01449          }
01450       }
01451       if (ast_test_flag(&opts, OPT_ANNOUNCE) && !ast_strlen_zero(opt_args[OPT_ARG_ANNOUNCE])) {
01452          /* Start autoservice on the other chan */
01453          res = ast_autoservice_start(chan);
01454          /* Now Stream the File */
01455          if (!res)
01456             res = ast_streamfile(peer, opt_args[OPT_ARG_ANNOUNCE], peer->language);
01457          if (!res) {
01458             digit = ast_waitstream(peer, AST_DIGIT_ANY); 
01459          }
01460          /* Ok, done. stop autoservice */
01461          res = ast_autoservice_stop(chan);
01462          if (digit > 0 && !res)
01463             res = ast_senddigit(chan, digit); 
01464          else
01465             res = digit;
01466 
01467       } else
01468          res = 0;
01469 
01470       if (chan && peer && ast_test_flag(&opts, OPT_GOTO) && !ast_strlen_zero(opt_args[OPT_ARG_GOTO])) {
01471          char *ch;
01472 
01473          for (ch = opt_args[OPT_ARG_GOTO]; *ch; ch++) {
01474             if (*ch == '^')
01475                *ch = '|';
01476          }
01477          ast_parseable_goto(chan, opt_args[OPT_ARG_GOTO]);
01478          ast_parseable_goto(peer, opt_args[OPT_ARG_GOTO]);
01479          peer->priority++;
01480          ast_pbx_start(peer);
01481          hanguptree(outgoing, NULL);
01482          LOCAL_USER_REMOVE(u);
01483          return 0;
01484       }
01485 
01486       if (ast_test_flag(&opts, OPT_CALLEE_MACRO) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_MACRO])) {
01487          char *ch;
01488 
01489          res = ast_autoservice_start(chan);
01490          if (res) {
01491             ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
01492             res = -1;
01493          }
01494 
01495          app = pbx_findapp("Macro");
01496 
01497          if (app && !res) {
01498             for (ch = opt_args[OPT_ARG_CALLEE_MACRO]; *ch; ch++) {
01499                if (*ch == '^')
01500                   *ch = '|';
01501             }
01502             res = pbx_exec(peer, app, opt_args[OPT_ARG_CALLEE_MACRO], 1);
01503             ast_log(LOG_DEBUG, "Macro exited with status %d\n", res);
01504             res = 0;
01505          } else {
01506             ast_log(LOG_ERROR, "Could not find application Macro\n");
01507             res = -1;
01508          }
01509 
01510          if (ast_autoservice_stop(chan) < 0) {
01511             ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
01512             res = -1;
01513          }
01514 
01515          if (!res) {
01516             if ((macro_result = pbx_builtin_getvar_helper(peer, "MACRO_RESULT"))) {
01517                if (!strcasecmp(macro_result, "BUSY")) {
01518                   ast_copy_string(status, macro_result, sizeof(status));
01519                   if (option_priority_jumping || ast_test_flag(&opts, OPT_PRIORITY_JUMP)) {
01520                      if (!ast_goto_if_exists(chan, NULL, NULL, chan->priority + 101)) {
01521                         ast_set_flag(peerflags, OPT_GO_ON);
01522                      }
01523                   } else
01524                      ast_set_flag(peerflags, OPT_GO_ON);
01525                   res = -1;
01526                }
01527                else if (!strcasecmp(macro_result, "CONGESTION") || !strcasecmp(macro_result, "CHANUNAVAIL")) {
01528                   ast_copy_string(status, macro_result, sizeof(status));
01529                   ast_set_flag(peerflags, OPT_GO_ON); 
01530                   res = -1;
01531                }
01532                else if (!strcasecmp(macro_result, "CONTINUE")) {
01533                   /* hangup peer and keep chan alive assuming the macro has changed 
01534                      the context / exten / priority or perhaps 
01535                      the next priority in the current exten is desired.
01536                   */
01537                   ast_set_flag(peerflags, OPT_GO_ON); 
01538                   res = -1;
01539                } else if (!strcasecmp(macro_result, "ABORT")) {
01540                   /* Hangup both ends unless the caller has the g flag */
01541                   res = -1;
01542                } else if (!strncasecmp(macro_result, "GOTO:",5) && (macro_transfer_dest = ast_strdupa(macro_result + 5))) {
01543                   res = -1;
01544                   /* perform a transfer to a new extension */
01545                   if (strchr(macro_transfer_dest,'^')) { /* context^exten^priority*/
01546                      /* no brainer mode... substitute ^ with | and feed it to builtin goto */
01547                      for (res=0;res<strlen(macro_transfer_dest);res++)
01548                         if (macro_transfer_dest[res] == '^')
01549                            macro_transfer_dest[res] = '|';
01550 
01551                      if (!ast_parseable_goto(chan, macro_transfer_dest))
01552                         ast_set_flag(peerflags, OPT_GO_ON);
01553 
01554                   }
01555                }
01556             }
01557          }
01558       }
01559 
01560       if (!res) {
01561          if (calldurationlimit > 0) {
01562             time_t now;
01563 
01564             time(&now);
01565             chan->whentohangup = now + calldurationlimit;
01566          }
01567          if (!ast_strlen_zero(dtmfcalled)) { 
01568             if (option_verbose > 2)
01569                ast_verbose(VERBOSE_PREFIX_3 "Sending DTMF '%s' to the called party.\n",dtmfcalled);
01570             res = ast_dtmf_stream(peer,chan,dtmfcalled,250);
01571          }
01572          if (!ast_strlen_zero(dtmfcalling)) {
01573             if (option_verbose > 2)
01574                ast_verbose(VERBOSE_PREFIX_3 "Sending DTMF '%s' to the calling party.\n",dtmfcalling);
01575             res = ast_dtmf_stream(chan,peer,dtmfcalling,250);
01576          }
01577       }
01578       
01579       if (!res) {
01580          memset(&config,0,sizeof(struct ast_bridge_config));
01581          if (play_to_caller)
01582             ast_set_flag(&(config.features_caller), AST_FEATURE_PLAY_WARNING);
01583          if (play_to_callee)
01584             ast_set_flag(&(config.features_callee), AST_FEATURE_PLAY_WARNING);
01585          if (ast_test_flag(peerflags, OPT_CALLEE_TRANSFER))
01586             ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
01587          if (ast_test_flag(peerflags, OPT_CALLER_TRANSFER))
01588             ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
01589          if (ast_test_flag(peerflags, OPT_CALLEE_HANGUP))
01590             ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
01591          if (ast_test_flag(peerflags, OPT_CALLER_HANGUP))
01592             ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
01593          if (ast_test_flag(peerflags, OPT_CALLEE_MONITOR))
01594             ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
01595          if (ast_test_flag(peerflags, OPT_CALLER_MONITOR)) 
01596             ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
01597 
01598          config.timelimit = timelimit;
01599          config.play_warning = play_warning;
01600          config.warning_freq = warning_freq;
01601          config.warning_sound = warning_sound;
01602          config.end_sound = end_sound;
01603          config.start_sound = start_sound;
01604          if (moh) {
01605             moh = 0;
01606             ast_moh_stop(chan);
01607          } else if (sentringing) {
01608             sentringing = 0;
01609             ast_indicate(chan, -1);
01610          }
01611          /* Be sure no generators are left on it */
01612          ast_deactivate_generator(chan);
01613          /* Make sure channels are compatible */
01614          res = ast_channel_make_compatible(chan, peer);
01615          if (res < 0) {
01616             ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", chan->name, peer->name);
01617             ast_hangup(peer);
01618             LOCAL_USER_REMOVE(u);
01619             return -1;
01620          }
01621          res = ast_bridge_call(chan,peer,&config);
01622          time(&end_time);
01623          snprintf(toast, sizeof(toast), "%ld", (long)(end_time - answer_time));
01624          pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", toast);
01625          
01626       } else {
01627          time(&end_time);
01628          res = -1;
01629       }
01630       snprintf(toast, sizeof(toast), "%ld", (long)(end_time - start_time));
01631       pbx_builtin_setvar_helper(chan, "DIALEDTIME", toast);
01632       
01633       if (res != AST_PBX_NO_HANGUP_PEER) {
01634          if (!chan->_softhangup)
01635             chan->hangupcause = peer->hangupcause;
01636          ast_hangup(peer);
01637       }
01638    }  
01639 out:
01640    if (moh) {
01641       moh = 0;
01642       ast_moh_stop(chan);
01643    } else if (sentringing) {
01644       sentringing = 0;
01645       ast_indicate(chan, -1);
01646    }
01647    hanguptree(outgoing, NULL);
01648    pbx_builtin_setvar_helper(chan, "DIALSTATUS", status);
01649    ast_log(LOG_DEBUG, "Exiting with DIALSTATUS=%s.\n", status);
01650    
01651    if ((ast_test_flag(peerflags, OPT_GO_ON)) && (!chan->_softhangup) && (res != AST_PBX_KEEPALIVE))
01652       res=0;
01653    
01654    LOCAL_USER_REMOVE(u);    
01655    
01656    return res;
01657 }

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

Definition at line 339 of file app_dial.c.

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

Referenced by dial_exec_full(), and wait_for_answer().

00340 {
00341    char *context;
00342    char *exten;
00343    if (!ast_strlen_zero(chan->macrocontext))
00344       context = chan->macrocontext;
00345    else
00346       context = chan->context;
00347 
00348    if (!ast_strlen_zero(chan->macroexten))
00349       exten = chan->macroexten;
00350    else
00351       exten = chan->exten;
00352 
00353    if (ast_get_hint(NULL, 0, name, namelen, chan, context, exten))
00354       return name;
00355    else
00356       return "";
00357 }

static void hanguptree ( struct localuser outgoing,
struct ast_channel exception 
) [static]

Definition at line 276 of file app_dial.c.

References ast_hangup(), localuser::chan, free, and localuser::next.

Referenced by dial_exec_full().

00277 {
00278    /* Hang up a tree of stuff */
00279    struct localuser *oo;
00280    while (outgoing) {
00281       /* Hangup any existing lines we have open */
00282       if (outgoing->chan && (outgoing->chan != exception))
00283          ast_hangup(outgoing->chan);
00284       oo = outgoing;
00285       outgoing=outgoing->next;
00286       free(oo);
00287    }
00288 }

char* key ( void   ) 

Returns the ASTERISK_GPL_KEY.

This returns the ASTERISK_GPL_KEY, signifiying that you agree to the terms of the GPL stated in the ASTERISK_GPL_KEY. Your module will not load if it does not return the EXACT message:

 char *key(void) {
         return ASTERISK_GPL_KEY;
 }

Returns:
ASTERISK_GPL_KEY

Definition at line 1806 of file app_dial.c.

References ASTERISK_GPL_KEY.

01807 {
01808    return ASTERISK_GPL_KEY;
01809 }

int load_module ( void   ) 

Initialize the module.

Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.

Returns:
int Always 0.

Definition at line 1784 of file app_dial.c.

References ast_register_application(), dial_exec(), and retrydial_exec().

01785 {
01786    int res;
01787 
01788    res = ast_register_application(app, dial_exec, synopsis, descrip);
01789    res |= ast_register_application(rapp, retrydial_exec, rsynopsis, rdescrip);
01790    
01791    return res;
01792 }

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

Definition at line 320 of file app_dial.c.

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

Referenced by retrydial_exec(), and wait_for_answer().

00321 {
00322    char rexten[2] = { exten, '\0' };
00323 
00324    if (context) {
00325       if (!ast_goto_if_exists(chan, context, rexten, pri))
00326          return 1;
00327    } else {
00328       if (!ast_goto_if_exists(chan, chan->context, rexten, pri))
00329          return 1;
00330       else if (!ast_strlen_zero(chan->macrocontext)) {
00331          if (!ast_goto_if_exists(chan, chan->macrocontext, rexten, pri))
00332             return 1;
00333       }
00334    }
00335    return 0;
00336 }

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

Definition at line 1666 of file app_dial.c.

References AST_DIGIT_ANY, AST_FLAG_MOH, ast_log(), ast_moh_start(), ast_moh_stop(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_waitfordigit(), ast_waitstream(), context, ast_channel::data, dial_exec_full(), LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_ERROR, LOG_WARNING, onedigit_goto(), OPT_DTMF_EXIT, and pbx_builtin_getvar_helper().

Referenced by load_module().

01667 {
01668    char *announce = NULL, *context = NULL, *dialdata = NULL;
01669    int sleep = 0, loops = 0, res = 0;
01670    struct localuser *u;
01671    struct ast_flags peerflags;
01672    
01673    if (ast_strlen_zero(data)) {
01674       ast_log(LOG_WARNING, "RetryDial requires an argument!\n");
01675       return -1;
01676    }  
01677 
01678    LOCAL_USER_ADD(u);
01679 
01680    announce = ast_strdupa(data); 
01681    if (!announce) {  
01682       ast_log(LOG_ERROR, "Out of memory!\n");
01683       LOCAL_USER_REMOVE(u);
01684       return -1;
01685    }
01686    
01687    memset(&peerflags, 0, sizeof(peerflags));
01688 
01689    if ((dialdata = strchr(announce, '|'))) {
01690       *dialdata = '\0';
01691       dialdata++;
01692       if ((sleep = atoi(dialdata))) {
01693          sleep *= 1000;
01694       } else {
01695          ast_log(LOG_ERROR, "%s requires the numerical argument <sleep>\n",rapp);
01696          LOCAL_USER_REMOVE(u);
01697          return -1;
01698       }
01699       if ((dialdata = strchr(dialdata, '|'))) {
01700          *dialdata = '\0';
01701          dialdata++;
01702          if (!(loops = atoi(dialdata))) {
01703             ast_log(LOG_ERROR, "%s requires the numerical argument <loops>\n",rapp);
01704             LOCAL_USER_REMOVE(u);
01705             return -1;
01706          }
01707       }
01708    }
01709    
01710    if ((dialdata = strchr(dialdata, '|'))) {
01711       *dialdata = '\0';
01712       dialdata++;
01713    } else {
01714       ast_log(LOG_ERROR, "%s requires more arguments\n",rapp);
01715       LOCAL_USER_REMOVE(u);
01716       return -1;
01717    }
01718       
01719    if (sleep < 1000)
01720       sleep = 10000;
01721    
01722    if (!loops)
01723       loops = -1;
01724    
01725    context = pbx_builtin_getvar_helper(chan, "EXITCONTEXT");
01726    
01727    while (loops) {
01728       chan->data = "Retrying";
01729       if (ast_test_flag(chan, AST_FLAG_MOH))
01730          ast_moh_stop(chan);
01731 
01732       if ((res = dial_exec_full(chan, dialdata, &peerflags)) == 0) {
01733          if (ast_test_flag(&peerflags, OPT_DTMF_EXIT)) {
01734             if (!(res = ast_streamfile(chan, announce, chan->language)))
01735                res = ast_waitstream(chan, AST_DIGIT_ANY);
01736             if (!res && sleep) {
01737                if (!ast_test_flag(chan, AST_FLAG_MOH))
01738                   ast_moh_start(chan, NULL);
01739                res = ast_waitfordigit(chan, sleep);
01740             }
01741          } else {
01742             if (!(res = ast_streamfile(chan, announce, chan->language)))
01743                res = ast_waitstream(chan, "");
01744             if (sleep) {
01745                if (!ast_test_flag(chan, AST_FLAG_MOH))
01746                   ast_moh_start(chan, NULL);
01747                if (!res) 
01748                   res = ast_waitfordigit(chan, sleep);
01749             }
01750          }
01751       }
01752 
01753       if (res < 0)
01754          break;
01755       else if (res > 0) { /* Trying to send the call elsewhere (1 digit ext) */
01756          if (onedigit_goto(chan, context, (char) res, 1)) {
01757             res = 0;
01758             break;
01759          }
01760       }
01761       loops--;
01762    }
01763    
01764    if (ast_test_flag(chan, AST_FLAG_MOH))
01765       ast_moh_stop(chan);
01766 
01767    LOCAL_USER_REMOVE(u);
01768    return loops ? res : 0;
01769 
01770 }

static void senddialevent ( struct ast_channel src,
struct ast_channel dst 
) [static]

Definition at line 359 of file app_dial.c.

References ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, EVENT_FLAG_CALL, manager_event(), ast_channel::name, and ast_channel::uniqueid.

Referenced by dial_exec_full(), and wait_for_answer().

00360 {
00361    manager_event(EVENT_FLAG_CALL, "Dial", 
00362             "Source: %s\r\n"
00363             "Destination: %s\r\n"
00364             "CallerID: %s\r\n"
00365             "CallerIDName: %s\r\n"
00366             "SrcUniqueID: %s\r\n"
00367             "DestUniqueID: %s\r\n",
00368             src->name, dst->name, src->cid.cid_num ? src->cid.cid_num : "<unknown>",
00369             src->cid.cid_name ? src->cid.cid_name : "<unknown>", src->uniqueid,
00370             dst->uniqueid);
00371 }

int unload_module ( void   ) 

Cleanup all module structures, sockets, etc.

This is called at exit. Any registrations and memory allocations need to be unregistered and free'd here. Nothing else will do these for you (until exit).

Returns:
Zero on success, or non-zero on error.

Definition at line 1772 of file app_dial.c.

References ast_unregister_application(), and STANDARD_HANGUP_LOCALUSERS.

01773 {
01774    int res;
01775 
01776    res = ast_unregister_application(app);
01777    res |= ast_unregister_application(rapp);
01778 
01779    STANDARD_HANGUP_LOCALUSERS;
01780    
01781    return res;
01782 }

int usecount ( void   ) 

Provides a usecount.

This function will be called by various parts of asterisk. Basically, all it has to do is to return a usecount when called. You will need to maintain your usecount within the module somewhere. The usecount should be how many channels provided by this module are in use.

Returns:
The module's usecount.

Definition at line 1799 of file app_dial.c.

References STANDARD_USECOUNT.

01800 {
01801    int res;
01802    STANDARD_USECOUNT(res);
01803    return res;
01804 }

static struct ast_channel* wait_for_answer ( struct ast_channel in,
struct localuser outgoing,
int *  to,
struct ast_flags peerflags,
int *  sentringing,
char *  status,
size_t  statussize,
int  busystart,
int  nochanstart,
int  congestionstart,
int  priority_jump,
int *  result 
) [static]

Definition at line 373 of file app_dial.c.

References ast_channel::accountcode, ast_call(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, AST_CAUSE_NORMAL_CLEARING, ast_channel_inherit_variables(), ast_channel_make_compatible(), ast_channel_sendhtml(), ast_clear_flag, AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_DISCONNECT, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_INBAND_INFO, AST_CONTROL_OFFHOOK, AST_CONTROL_PROCEEDING, AST_CONTROL_PROGRESS, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, AST_CONTROL_VIDUPDATE, ast_copy_flags, ast_deactivate_generator(), AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_HTML, AST_FRAME_IMAGE, AST_FRAME_TEXT, AST_FRAME_VOICE, ast_frfree(), ast_goto_if_exists(), ast_hangup(), ast_indicate(), ast_log(), AST_MAX_EXTENSION, AST_MAX_FORWARDS, AST_MAX_WATCHERS, ast_read(), ast_request(), ast_set_callerid(), AST_STATE_UP, ast_strlen_zero(), ast_test_flag, ast_verbose(), ast_waitfor_n(), ast_write(), ast_channel::cdrflags, localuser::chan, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_name, ast_callerid::cid_num, ast_channel::context, context, ast_frame::data, ast_frame::datalen, DIAL_NOFORWARDHTML, DIAL_STILLGOING, ast_channel::exten, ast_frame::frametype, free, get_cid_name(), HANDLE_CAUSE, ast_channel::hangupcause, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, ast_channel::macroexten, ast_channel::name, ast_channel::nativeformats, ast_channel::next, localuser::next, onedigit_goto(), OPT_CALLEE_HANGUP, OPT_CALLEE_MONITOR, OPT_CALLEE_TRANSFER, OPT_CALLER_HANGUP, OPT_CALLER_MONITOR, OPT_CALLER_TRANSFER, OPT_DTMF_EXIT, OPT_FORCECLID, OPT_MUSICBACK, OPT_ORIGINAL_CLID, OPT_RINGBACK, option_priority_jumping, option_verbose, pbx_builtin_getvar_helper(), senddialevent(), strdup, ast_frame::subclass, ast_channel::tech, VERBOSE_PREFIX_2, and VERBOSE_PREFIX_3.

Referenced by dial_exec_full(), and try_calling().

00374 {
00375    struct localuser *o;
00376    int found;
00377    int numlines;
00378    int numbusy = busystart;
00379    int numcongestion = congestionstart;
00380    int numnochan = nochanstart;
00381    int prestart = busystart + congestionstart + nochanstart;
00382    int cause;
00383    int orig = *to;
00384    struct ast_frame *f;
00385    struct ast_channel *peer = NULL;
00386    struct ast_channel *watchers[AST_MAX_WATCHERS];
00387    int pos;
00388    int single;
00389    struct ast_channel *winner;
00390    char *context = NULL;
00391    char cidname[AST_MAX_EXTENSION];
00392 
00393    single = (outgoing && !outgoing->next && !ast_test_flag(outgoing, OPT_MUSICBACK | OPT_RINGBACK));
00394    
00395    if (single) {
00396       /* Turn off hold music, etc */
00397       ast_deactivate_generator(in);
00398       /* If we are calling a single channel, make them compatible for in-band tone purpose */
00399       ast_channel_make_compatible(outgoing->chan, in);
00400    }
00401    
00402    
00403    while (*to && !peer) {
00404       o = outgoing;
00405       found = -1;
00406       pos = 1;
00407       numlines = prestart;
00408       watchers[0] = in;
00409       while (o) {
00410          /* Keep track of important channels */
00411          if (ast_test_flag(o, DIAL_STILLGOING) && o->chan) {
00412             watchers[pos++] = o->chan;
00413             found = 1;
00414          }
00415          o = o->next;
00416          numlines++;
00417       }
00418       if (found < 0) {
00419          if (numlines == (numbusy + numcongestion + numnochan)) {
00420             if (option_verbose > 2)
00421                ast_verbose( VERBOSE_PREFIX_2 "Everyone is busy/congested at this time (%d:%d/%d/%d)\n", numlines, numbusy, numcongestion, numnochan);
00422             if (numbusy)
00423                strcpy(status, "BUSY"); 
00424             else if (numcongestion)
00425                strcpy(status, "CONGESTION");
00426             else if (numnochan)
00427                strcpy(status, "CHANUNAVAIL");
00428             if (option_priority_jumping || priority_jump)
00429                ast_goto_if_exists(in, in->context, in->exten, in->priority + 101);
00430          } else {
00431             if (option_verbose > 2)
00432                ast_verbose( VERBOSE_PREFIX_2 "No one is available to answer at this time (%d:%d/%d/%d)\n", numlines, numbusy, numcongestion, numnochan);
00433          }
00434          *to = 0;
00435          return NULL;
00436       }
00437       winner = ast_waitfor_n(watchers, pos, to);
00438       o = outgoing;
00439       while (o) {
00440          if (ast_test_flag(o, DIAL_STILLGOING) && o->chan && (o->chan->_state == AST_STATE_UP)) {
00441             if (!peer) {
00442                if (option_verbose > 2)
00443                   ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
00444                peer = o->chan;
00445                ast_copy_flags(peerflags, o,
00446                          OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
00447                          OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
00448                          OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
00449                          DIAL_NOFORWARDHTML);
00450             }
00451          } else if (o->chan && (o->chan == winner)) {
00452             if (!ast_strlen_zero(o->chan->call_forward)) {
00453                char tmpchan[256];
00454                char *stuff;
00455                char *tech;
00456                ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
00457                if ((stuff = strchr(tmpchan, '/'))) {
00458                   *stuff = '\0';
00459                   stuff++;
00460                   tech = tmpchan;
00461                } else {
00462                   snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
00463                   stuff = tmpchan;
00464                   tech = "Local";
00465                }
00466                /* Before processing channel, go ahead and check for forwarding */
00467                o->forwards++;
00468                if (o->forwards < AST_MAX_FORWARDS) {
00469                   if (option_verbose > 2)
00470                      ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
00471                   /* Setup parameters */
00472                   o->chan = ast_request(tech, in->nativeformats, stuff, &cause);
00473                   if (!o->chan)
00474                      ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
00475                   else
00476                      ast_channel_inherit_variables(in, o->chan);
00477                } else {
00478                   if (option_verbose > 2)
00479                      ast_verbose(VERBOSE_PREFIX_3 "Too many forwards from %s\n", o->chan->name);
00480                   cause = AST_CAUSE_CONGESTION;
00481                   o->chan = NULL;
00482                }
00483                if (!o->chan) {
00484                   ast_clear_flag(o, DIAL_STILLGOING); 
00485                   HANDLE_CAUSE(cause, in);
00486                } else {
00487                   if (o->chan->cid.cid_num)
00488                      free(o->chan->cid.cid_num);
00489                   o->chan->cid.cid_num = NULL;
00490                   if (o->chan->cid.cid_name)
00491                      free(o->chan->cid.cid_name);
00492                   o->chan->cid.cid_name = NULL;
00493 
00494                   if (ast_test_flag(o, OPT_FORCECLID)) {
00495                      char *newcid = NULL;
00496 
00497                      if (!ast_strlen_zero(in->macroexten))
00498                         newcid = in->macroexten;
00499                      else
00500                         newcid = in->exten;
00501                      o->chan->cid.cid_num = strdup(newcid);
00502                      ast_copy_string(o->chan->accountcode, winner->accountcode, sizeof(o->chan->accountcode));
00503                      o->chan->cdrflags = winner->cdrflags;
00504                      if (!o->chan->cid.cid_num)
00505                         ast_log(LOG_WARNING, "Out of memory\n");
00506                   } else {
00507                      if (in->cid.cid_num) {
00508                         o->chan->cid.cid_num = strdup(in->cid.cid_num);
00509                         if (!o->chan->cid.cid_num)
00510                            ast_log(LOG_WARNING, "Out of memory\n");  
00511                      }
00512                      if (in->cid.cid_name) {
00513                         o->chan->cid.cid_name = strdup(in->cid.cid_name);
00514                         if (!o->chan->cid.cid_name)
00515                            ast_log(LOG_WARNING, "Out of memory\n");  
00516                      }
00517                      ast_copy_string(o->chan->accountcode, in->accountcode, sizeof(o->chan->accountcode));
00518                      o->chan->cdrflags = in->cdrflags;
00519                   }
00520 
00521                   if (in->cid.cid_ani) {
00522                      if (o->chan->cid.cid_ani)
00523                         free(o->chan->cid.cid_ani);
00524                      o->chan->cid.cid_ani = strdup(in->cid.cid_ani);
00525                      if (!o->chan->cid.cid_ani)
00526                         ast_log(LOG_WARNING, "Out of memory\n");
00527                   }
00528                   if (o->chan->cid.cid_rdnis) 
00529                      free(o->chan->cid.cid_rdnis);
00530                   if (!ast_strlen_zero(in->macroexten))
00531                      o->chan->cid.cid_rdnis = strdup(in->macroexten);
00532                   else
00533                      o->chan->cid.cid_rdnis = strdup(in->exten);
00534                   if (ast_call(o->chan, tmpchan, 0)) {
00535                      ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
00536                      ast_clear_flag(o, DIAL_STILLGOING); 
00537                      ast_hangup(o->chan);
00538                      o->chan = NULL;
00539                      numnochan++;
00540                   } else {
00541                      senddialevent(in, o->chan);
00542                      /* After calling, set callerid to extension */
00543                      if (!ast_test_flag(peerflags, OPT_ORIGINAL_CLID))
00544                         ast_set_callerid(o->chan, ast_strlen_zero(in->macroexten) ? in->exten : in->macroexten, get_cid_name(cidname, sizeof(cidname), in), NULL);
00545                   }
00546                }
00547                /* Hangup the original channel now, in case we needed it */
00548                ast_hangup(winner);
00549                continue;
00550             }
00551             f = ast_read(winner);
00552             if (f) {
00553                if (f->frametype == AST_FRAME_CONTROL) {
00554                   switch(f->subclass) {
00555                   case AST_CONTROL_ANSWER:
00556                      /* This is our guy if someone answered. */
00557                      if (!peer) {
00558                         if (option_verbose > 2)
00559                            ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
00560                         peer = o->chan;
00561                         ast_copy_flags(peerflags, o,
00562                                   OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
00563                                   OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
00564                                   OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
00565                                   DIAL_NOFORWARDHTML);
00566                         ast_indicate(in, AST_CONTROL_ANSWER);
00567 
00568                      }
00569                      /* If call has been answered, then the eventual hangup is likely to be normal hangup */
00570                      in->hangupcause = AST_CAUSE_NORMAL_CLEARING;
00571                      o->chan->hangupcause = AST_CAUSE_NORMAL_CLEARING;
00572 
00573                      break;
00574                   case AST_CONTROL_BUSY:
00575                      if (option_verbose > 2)
00576                         ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
00577                      in->hangupcause = o->chan->hangupcause;
00578                      ast_hangup(o->chan);
00579                      o->chan = NULL;
00580                      ast_clear_flag(o, DIAL_STILLGOING); 
00581                      HANDLE_CAUSE(AST_CAUSE_BUSY, in);
00582                      break;
00583                   case AST_CONTROL_CONGESTION:
00584                      if (option_verbose > 2)
00585                         ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
00586                      in->hangupcause = o->chan->hangupcause;
00587                      ast_hangup(o->chan);
00588                      o->chan = NULL;
00589                      ast_clear_flag(o, DIAL_STILLGOING);
00590                      HANDLE_CAUSE(AST_CAUSE_CONGESTION, in);
00591                      break;
00592                   case AST_CONTROL_RINGING:
00593                      if (option_verbose > 2)
00594                         ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
00595                      if (!(*sentringing) && !ast_test_flag(outgoing, OPT_MUSICBACK)) {
00596                         ast_indicate(in, AST_CONTROL_RINGING);
00597                         (*sentringing)++;
00598                      }
00599                      break;
00600                   case AST_CONTROL_PROGRESS:
00601                      if (option_verbose > 2)
00602                         ast_verbose ( VERBOSE_PREFIX_3 "%s is making progress passing it to %s\n", o->chan->name,in->name);
00603                      if (!ast_test_flag(outgoing, OPT_RINGBACK))
00604                         ast_indicate(in, AST_CONTROL_PROGRESS);
00605                      break;
00606                   case AST_CONTROL_VIDUPDATE:
00607                      if (option_verbose > 2)
00608                         ast_verbose ( VERBOSE_PREFIX_3 "%s requested a video update, passing it to %s\n", o->chan->name,in->name);
00609                      ast_indicate(in, AST_CONTROL_VIDUPDATE);
00610                      break;
00611                   case AST_CONTROL_PROCEEDING:
00612                      if (option_verbose > 2)
00613                         ast_verbose ( VERBOSE_PREFIX_3 "%s is proceeding passing it to %s\n", o->chan->name,in->name);
00614                      if (!ast_test_flag(outgoing, OPT_RINGBACK))
00615                         ast_indicate(in, AST_CONTROL_PROCEEDING);
00616                      break;
00617                   case AST_CONTROL_HOLD:
00618                      if (option_verbose > 2)
00619                         ast_verbose(VERBOSE_PREFIX_3 "Call on %s placed on hold\n", o->chan->name);
00620                      ast_indicate(in, AST_CONTROL_HOLD);
00621                      break;
00622                   case AST_CONTROL_UNHOLD:
00623                      if (option_verbose > 2)
00624                         ast_verbose(VERBOSE_PREFIX_3 "Call on %s left from hold\n", o->chan->name);
00625                      ast_indicate(in, AST_CONTROL_UNHOLD);
00626                      break;
00627                   case AST_CONTROL_INBAND_INFO:
00628                      if (option_verbose > 2)
00629                         ast_verbose(VERBOSE_PREFIX_3 "Inband information available\n", o->chan->name);
00630                      ast_indicate(in, AST_CONTROL_INBAND_INFO);
00631                      break;
00632                   case AST_CONTROL_DISCONNECT:
00633                      if (option_verbose > 2)
00634                         ast_verbose(VERBOSE_PREFIX_3 "Call disconnected\n", o->chan->name);
00635                      in->hangupcause = o->chan->hangupcause;
00636                      ast_indicate(in, AST_CONTROL_DISCONNECT);
00637                      break;
00638                   case AST_CONTROL_OFFHOOK:
00639                   case AST_CONTROL_FLASH:
00640                      /* Ignore going off hook and flash */
00641                      break;
00642                   case -1:
00643                      if (!ast_test_flag(outgoing, OPT_RINGBACK | OPT_MUSICBACK)) {
00644                         if (option_verbose > 2)
00645                            ast_verbose( VERBOSE_PREFIX_3 "%s stopped sounds\n", o->chan->name);
00646                         ast_indicate(in, -1);
00647                         (*sentringing) = 0;
00648                      }
00649                      break;
00650                   default:
00651                      ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
00652                   }
00653                } else if (single && (f->frametype == AST_FRAME_VOICE) && 
00654                         !(ast_test_flag(outgoing, OPT_RINGBACK|OPT_MUSICBACK))) {
00655                   if (ast_write(in, f)) 
00656                      ast_log(LOG_DEBUG, "Unable to forward frame\n");
00657                } else if (single && (f->frametype == AST_FRAME_IMAGE) && 
00658                         !(ast_test_flag(outgoing, OPT_RINGBACK|OPT_MUSICBACK))) {
00659                   if (ast_write(in, f))
00660                      ast_log(LOG_DEBUG, "Unable to forward image\n");
00661                } else if (single && (f->frametype == AST_FRAME_TEXT) && 
00662                         !(ast_test_flag(outgoing, OPT_RINGBACK|OPT_MUSICBACK))) {
00663                   if (ast_write(in, f))
00664                      ast_log(LOG_DEBUG, "Unable to text\n");
00665                } else if (single && (f->frametype == AST_FRAME_HTML) && !ast_test_flag(outgoing, DIAL_NOFORWARDHTML))
00666                   ast_channel_sendhtml(in, f->subclass, f->data, f->datalen);
00667 
00668                ast_frfree(f);
00669             } else {
00670                in->hangupcause = o->chan->hangupcause;
00671                ast_hangup(o->chan);
00672                o->chan = NULL;
00673                ast_clear_flag(o, DIAL_STILLGOING);
00674                HANDLE_CAUSE(in->hangupcause, in);
00675             }
00676          }
00677          o = o->next;
00678       }
00679       if (winner == in) {
00680          f = ast_read(in);
00681 #if 0
00682          if (f && (f->frametype != AST_FRAME_VOICE))
00683             printf("Frame type: %d, %d\n", f->frametype, f->subclass);
00684          else if (!f || (f->frametype != AST_FRAME_VOICE))
00685             printf("Hangup received on %s\n", in->name);
00686 #endif
00687          if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
00688             /* Got hung up */
00689             *to=-1;
00690             strcpy(status, "CANCEL");
00691             if (f)
00692                ast_frfree(f);
00693             return NULL;
00694          }
00695 
00696          if (f && (f->frametype == AST_FRAME_DTMF)) {
00697             if (ast_test_flag(peerflags, OPT_DTMF_EXIT)) {
00698                context = pbx_builtin_getvar_helper(in, "EXITCONTEXT");
00699                if (onedigit_goto(in, context, (char) f->subclass, 1)) {
00700                   if (option_verbose > 3)
00701                      ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
00702                   *to=0;
00703                   *result = f->subclass;
00704                   strcpy(status, "CANCEL");
00705                   ast_frfree(f);
00706                   return NULL;
00707                }
00708             }
00709 
00710             if (ast_test_flag(peerflags, OPT_CALLER_HANGUP) && 
00711                     (f->subclass == '*')) { /* hmm it it not guarenteed to be '*' anymore. */
00712                if (option_verbose > 3)
00713                   ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
00714                *to=0;
00715                strcpy(status, "CANCEL");
00716                ast_frfree(f);
00717                return NULL;
00718             }
00719          }
00720 
00721          /* Forward HTML stuff */
00722          if (single && f && (f->frametype == AST_FRAME_HTML) && !ast_test_flag(outgoing, DIAL_NOFORWARDHTML)) 
00723             ast_channel_sendhtml(outgoing->chan, f->subclass, f->data, f->datalen);
00724          
00725 
00726          if (single && ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_DTMF)))  {
00727             if (ast_write(outgoing->chan, f))
00728                ast_log(LOG_WARNING, "Unable to forward voice\n");
00729          }
00730          if (single && (f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_VIDUPDATE)) {
00731             if (option_verbose > 2)
00732                ast_verbose ( VERBOSE_PREFIX_3 "%s requested a video update, passing it to %s\n", in->name,outgoing->chan->name);
00733             ast_indicate(outgoing->chan, AST_CONTROL_VIDUPDATE);
00734          }
00735          ast_frfree(f);
00736       }
00737       if (!*to && (option_verbose > 2))
00738          ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
00739    }
00740 
00741    return peer;
00742    
00743 }


Variable Documentation

char* app = "Dial" [static]

Definition at line 62 of file app_dial.c.

char* descrip [static]

Definition at line 66 of file app_dial.c.

enum { ... } dial_exec_option_args

enum { ... } dial_exec_option_flags

LOCAL_USER_DECL

Definition at line 274 of file app_dial.c.

char* rapp = "RetryDial" [static]

Definition at line 178 of file app_dial.c.

char* rdescrip [static]

Definition at line 180 of file app_dial.c.

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

Definition at line 179 of file app_dial.c.

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

Definition at line 64 of file app_dial.c.

char* tdesc = "Dialing Application" [static]

Definition at line 60 of file app_dial.c.


Generated on Sat Sep 16 05:47:49 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.7