Sun Aug 6 15:03:13 2006

Asterisk developer's documentation


Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

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

Include dependency graph for app_dial.c:

Go to the source code of this file.

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

Referenced by dial_exec_full(), and wait_for_answer().

#define AST_MAX_WATCHERS   256
 

Definition at line 291 of file app_dial.c.

Referenced by wait_for_answer().

#define DIAL_NOFORWARDHTML   (1 << 31)
 

Definition at line 220 of file app_dial.c.

Referenced by dial_exec_full(), and wait_for_answer().

#define DIAL_STILLGOING   (1 << 30)
 

Definition at line 219 of file app_dial.c.

Referenced by dial_exec_full(), and wait_for_answer().

#define HANDLE_CAUSE cause,
chan   ) 
 

Definition at line 293 of file app_dial.c.

Referenced by dial_exec_full(), and wait_for_answer().


Enumeration Type Documentation

anonymous enum
 

Enumeration values:
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 192 of file app_dial.c.

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

anonymous enum
 

Enumeration values:
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 222 of file app_dial.c.

00222      {
00223    OPT_ARG_ANNOUNCE = 0,
00224    OPT_ARG_SENDDTMF,
00225    OPT_ARG_GOTO,
00226    OPT_ARG_DURATION_LIMIT,
00227    OPT_ARG_MUSICBACK,
00228    OPT_ARG_CALLEE_MACRO,
00229    OPT_ARG_PRIVACY,
00230    OPT_ARG_DURATION_STOP,
00231    /* note: this entry _MUST_ be the last one in the enum */
00232    OPT_ARG_ARRAY_SIZE,
00233 } 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 1773 of file app_dial.c.

References tdesc.

01774 {
01775    return tdesc;
01776 }

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

Definition at line 1638 of file app_dial.c.

References dial_exec_full().

Referenced by load_module().

01639 {
01640    struct ast_flags peerflags;
01641    memset(&peerflags, 0, sizeof(peerflags));
01642    return dial_exec_full(chan, data, &peerflags);
01643 }

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

Definition at line 730 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_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, 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, 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, and ast_bridge_config::warning_sound.

Referenced by dial_exec(), and retrydial_exec().

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

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

Definition at line 338 of file app_dial.c.

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

Referenced by dial_exec_full(), and wait_for_answer().

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

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

Definition at line 275 of file app_dial.c.

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

Referenced by dial_exec_full().

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

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

References ASTERISK_GPL_KEY.

01786 {
01787    return ASTERISK_GPL_KEY;
01788 }

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

References app, ast_register_application(), descrip, dial_exec(), rapp, rdescrip, retrydial_exec(), rsynopsis, and synopsis.

01764 {
01765    int res;
01766 
01767    res = ast_register_application(app, dial_exec, synopsis, descrip);
01768    res |= ast_register_application(rapp, retrydial_exec, rsynopsis, rdescrip);
01769    
01770    return res;
01771 }

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

Definition at line 319 of file app_dial.c.

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

Referenced by retrydial_exec(), and wait_for_answer().

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

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

Definition at line 1645 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, dial_exec_full(), LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_ERROR, LOG_WARNING, onedigit_goto(), OPT_DTMF_EXIT, pbx_builtin_getvar_helper(), and rapp.

Referenced by load_module().

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

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

Definition at line 358 of file app_dial.c.

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

Referenced by dial_exec_full(), and wait_for_answer().

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

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

References app, ast_unregister_application(), rapp, and STANDARD_HANGUP_LOCALUSERS.

01752 {
01753    int res;
01754 
01755    res = ast_unregister_application(app);
01756    res |= ast_unregister_application(rapp);
01757 
01758    STANDARD_HANGUP_LOCALUSERS;
01759    
01760    return res;
01761 }

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

References STANDARD_USECOUNT.

01779 {
01780    int res;
01781    STANDARD_USECOUNT(res);
01782    return res;
01783 }

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 372 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_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, 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().

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


Variable Documentation

char* app = "Dial" [static]
 

Definition at line 61 of file app_dial.c.

char* descrip [static]
 

Definition at line 65 of file app_dial.c.

enum { ... } dial_exec_option_args
 

enum { ... } dial_exec_option_flags
 

LOCAL_USER_DECL
 

Definition at line 273 of file app_dial.c.

char* rapp = "RetryDial" [static]
 

Definition at line 177 of file app_dial.c.

Referenced by load_module(), retrydial_exec(), and unload_module().

char* rdescrip [static]
 

Definition at line 179 of file app_dial.c.

Referenced by load_module().

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

Definition at line 178 of file app_dial.c.

Referenced by load_module().

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

Definition at line 63 of file app_dial.c.

char* tdesc = "Dialing Application" [static]
 

Definition at line 59 of file app_dial.c.


Generated on Sun Aug 6 15:03:15 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.2