Mon Mar 20 08:25:46 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"

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.
int dial_exec (struct ast_channel *chan, void *data)
int dial_exec_full (struct ast_channel *chan, void *data, struct ast_flags *peerflags)
char * get_cid_name (char *name, int namelen, struct ast_channel *chan)
void hanguptree (struct localuser *outgoing, struct ast_channel *exception)
char * key ()
 Returns the ASTERISK_GPL_KEY.
int load_module (void)
 Initialize the module.
int onedigit_goto (struct ast_channel *chan, char *context, char exten, int pri)
int retrydial_exec (struct ast_channel *chan, void *data)
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.
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

char * app = "Dial"
char * descrip
enum { ... }  dial_exec_option_args
enum { ... }  dial_exec_option_flags
 LOCAL_USER_DECL
char * rapp = "RetryDial"
char * rdescrip
char * rsynopsis = "Place a call, retrying on failure allowing optional exit extension."
char * synopsis = "Place a call and connect to the current channel"
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 285 of file app_dial.c.

#define AST_MAX_WATCHERS   256
 

Definition at line 287 of file app_dial.c.

#define DIAL_NOFORWARDHTML   (1 << 31)
 

Definition at line 216 of file app_dial.c.

Referenced by dial_exec_full(), and wait_for_answer().

#define DIAL_STILLGOING   (1 << 30)
 

Definition at line 215 of file app_dial.c.

Referenced by dial_exec_full(), and wait_for_answer().

#define HANDLE_CAUSE cause,
chan   ) 
 

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

00188      {
00189    OPT_ANNOUNCE = (1 << 0),
00190    OPT_RESETCDR = (1 << 1),
00191    OPT_DTMF_EXIT = (1 << 2),
00192    OPT_SENDDTMF = (1 << 3),
00193    OPT_FORCECLID = (1 << 4),
00194    OPT_GO_ON = (1 << 5),
00195    OPT_CALLEE_HANGUP = (1 << 6),
00196    OPT_CALLER_HANGUP = (1 << 7),
00197    OPT_PRIORITY_JUMP = (1 << 8),
00198    OPT_DURATION_LIMIT = (1 << 9),
00199    OPT_MUSICBACK = (1 << 10),
00200    OPT_CALLEE_MACRO = (1 << 11),
00201    OPT_SCREEN_NOINTRO = (1 << 12),
00202    OPT_SCREEN_NOCLID = (1 << 13),
00203    OPT_ORIGINAL_CLID = (1 << 14),
00204    OPT_SCREENING = (1 << 15),
00205    OPT_PRIVACY = (1 << 16),
00206    OPT_RINGBACK = (1 << 17),
00207    OPT_DURATION_STOP = (1 << 18),
00208    OPT_CALLEE_TRANSFER = (1 << 19),
00209    OPT_CALLER_TRANSFER = (1 << 20),
00210    OPT_CALLEE_MONITOR = (1 << 21),
00211    OPT_CALLER_MONITOR = (1 << 22),
00212    OPT_GOTO = (1 << 23),
00213 } 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 218 of file app_dial.c.

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

01733 {
01734    return tdesc;
01735 }

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

Definition at line 1597 of file app_dial.c.

References dial_exec_full().

Referenced by load_module().

01598 {
01599    struct ast_flags peerflags;
01600    memset(&peerflags, 0, sizeof(peerflags));
01601    return dial_exec_full(chan, data, &peerflags);
01602 }

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

Definition at line 722 of file app_dial.c.

References ast_channel::_softhangup, ast_channel::_state, ast_channel::accountcode, ast_channel::adsicpe, app, ast_channel::appl, 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_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_moh_start(), ast_moh_stop(), ast_parseable_goto(), 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_request(), ast_senddigit(), ast_set2_flag, ast_set_callerid(), ast_set_flag, ast_shrink_phone_number(), AST_STANDARD_APP_ARGS, 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, ast_channel::data, DIAL_NOFORWARDHTML, DIAL_STILLGOING, ast_bridge_config::end_sound, ast_channel::exten, ast_bridge_config::features_callee, ast_bridge_config::features_caller, 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, ast_channel::musicclass, ast_channel::name, ast_channel::nativeformats, ast_channel::next, OPT_ANNOUNCE, OPT_ARG_ANNOUNCE, 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_priority_jumping, option_verbose, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), ast_bridge_config::play_warning, ast_channel::priority, result, senddialevent(), ast_bridge_config::start_sound, 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().

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

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

Definition at line 332 of file app_dial.c.

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

Referenced by dial_exec_full(), and wait_for_answer().

00333 {
00334    char *context;
00335    char *exten;
00336    if (!ast_strlen_zero(chan->macrocontext))
00337       context = chan->macrocontext;
00338    else
00339       context = chan->context;
00340 
00341    if (!ast_strlen_zero(chan->macroexten))
00342       exten = chan->macroexten;
00343    else
00344       exten = chan->exten;
00345 
00346    if (ast_get_hint(NULL, 0, name, namelen, chan, context, exten))
00347       return name;
00348    else
00349       return "";
00350 }

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

Definition at line 271 of file app_dial.c.

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

Referenced by dial_exec_full().

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

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

01745 {
01746    return ASTERISK_GPL_KEY;
01747 }

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

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

01723 {
01724    int res;
01725 
01726    res = ast_register_application(app, dial_exec, synopsis, descrip);
01727    res |= ast_register_application(rapp, retrydial_exec, rsynopsis, rdescrip);
01728    
01729    return res;
01730 }

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

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

00314 {
00315    char rexten[2] = { exten, '\0' };
00316 
00317    if (context) {
00318       if (!ast_goto_if_exists(chan, context, rexten, pri))
00319          return 1;
00320    } else {
00321       if (!ast_goto_if_exists(chan, chan->context, rexten, pri))
00322          return 1;
00323       else if (!ast_strlen_zero(chan->macrocontext)) {
00324          if (!ast_goto_if_exists(chan, chan->macrocontext, rexten, pri))
00325             return 1;
00326       }
00327    }
00328    return 0;
00329 }

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

Definition at line 1604 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(), ast_channel::data, dial_exec_full(), ast_channel::language, 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().

01605 {
01606    char *announce = NULL, *context = NULL, *dialdata = NULL;
01607    int sleep = 0, loops = 0, res = 0;
01608    struct localuser *u;
01609    struct ast_flags peerflags;
01610    
01611    if (ast_strlen_zero(data)) {
01612       ast_log(LOG_WARNING, "RetryDial requires an argument!\n");
01613       return -1;
01614    }  
01615 
01616    LOCAL_USER_ADD(u);
01617 
01618    announce = ast_strdupa(data); 
01619    if (!announce) {  
01620       ast_log(LOG_ERROR, "Out of memory!\n");
01621       LOCAL_USER_REMOVE(u);
01622       return -1;
01623    }
01624    
01625    memset(&peerflags, 0, sizeof(peerflags));
01626 
01627    if ((dialdata = strchr(announce, '|'))) {
01628       *dialdata = '\0';
01629       dialdata++;
01630       if ((sleep = atoi(dialdata))) {
01631          sleep *= 1000;
01632       } else {
01633          ast_log(LOG_ERROR, "%s requires the numerical argument <sleep>\n",rapp);
01634          LOCAL_USER_REMOVE(u);
01635          return -1;
01636       }
01637       if ((dialdata = strchr(dialdata, '|'))) {
01638          *dialdata = '\0';
01639          dialdata++;
01640          if (!(loops = atoi(dialdata))) {
01641             ast_log(LOG_ERROR, "%s requires the numerical argument <loops>\n",rapp);
01642             LOCAL_USER_REMOVE(u);
01643             return -1;
01644          }
01645       }
01646    }
01647    
01648    if ((dialdata = strchr(dialdata, '|'))) {
01649       *dialdata = '\0';
01650       dialdata++;
01651    } else {
01652       ast_log(LOG_ERROR, "%s requires more arguments\n",rapp);
01653       LOCAL_USER_REMOVE(u);
01654       return -1;
01655    }
01656       
01657    if (sleep < 1000)
01658       sleep = 10000;
01659    
01660    if (!loops)
01661       loops = -1;
01662    
01663    context = pbx_builtin_getvar_helper(chan, "EXITCONTEXT");
01664    
01665    while (loops) {
01666       chan->data = "Retrying";
01667       if (ast_test_flag(chan, AST_FLAG_MOH))
01668          ast_moh_stop(chan);
01669 
01670       if ((res = dial_exec_full(chan, dialdata, &peerflags)) == 0) {
01671          if (ast_test_flag(&peerflags, OPT_DTMF_EXIT)) {
01672             if (!(res = ast_streamfile(chan, announce, chan->language)))
01673                res = ast_waitstream(chan, AST_DIGIT_ANY);
01674             if (!res && sleep) {
01675                if (!ast_test_flag(chan, AST_FLAG_MOH))
01676                   ast_moh_start(chan, NULL);
01677                res = ast_waitfordigit(chan, sleep);
01678             }
01679          } else {
01680             if (!(res = ast_streamfile(chan, announce, chan->language)))
01681                res = ast_waitstream(chan, "");
01682             if (sleep) {
01683                if (!ast_test_flag(chan, AST_FLAG_MOH))
01684                   ast_moh_start(chan, NULL);
01685                if (!res) 
01686                   res = ast_waitfordigit(chan, sleep);
01687             }
01688          }
01689       }
01690 
01691       if (res < 0)
01692          break;
01693       else if (res > 0) { /* Trying to send the call elsewhere (1 digit ext) */
01694          if (onedigit_goto(chan, context, (char) res, 1)) {
01695             res = 0;
01696             break;
01697          }
01698       }
01699       loops--;
01700    }
01701    
01702    if (ast_test_flag(chan, AST_FLAG_MOH))
01703       ast_moh_stop(chan);
01704 
01705    LOCAL_USER_REMOVE(u);
01706    return loops ? res : 0;
01707 
01708 }

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

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

00353 {
00354    manager_event(EVENT_FLAG_CALL, "Dial", 
00355             "Source: %s\r\n"
00356             "Destination: %s\r\n"
00357             "CallerID: %s\r\n"
00358             "CallerIDName: %s\r\n"
00359             "SrcUniqueID: %s\r\n"
00360             "DestUniqueID: %s\r\n",
00361             src->name, dst->name, src->cid.cid_num ? src->cid.cid_num : "<unknown>",
00362             src->cid.cid_name ? src->cid.cid_name : "<unknown>", src->uniqueid,
00363             dst->uniqueid);
00364 }

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

References app, ast_unregister_application(), and rapp.

01711 {
01712    int res;
01713 
01714    res = ast_unregister_application(app);
01715    res |= ast_unregister_application(rapp);
01716 
01717    STANDARD_HANGUP_LOCALUSERS;
01718    
01719    return res;
01720 }

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

References STANDARD_USECOUNT.

01738 {
01739    int res;
01740    STANDARD_USECOUNT(res);
01741    return res;
01742 }

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

References ast_channel::_state, ast_channel::accountcode, ast_call(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, ast_channel_make_compatible(), ast_channel_sendhtml(), ast_clear_flag, AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HOLD, AST_CONTROL_OFFHOOK, AST_CONTROL_PROCEEDING, AST_CONTROL_PROGRESS, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, AST_CONTROL_VIDUPDATE, ast_copy_flags, ast_deactivate_generator(), ast_frfree(), ast_goto_if_exists(), ast_hangup(), ast_indicate(), ast_log(), ast_read(), ast_request(), ast_set_callerid(), ast_strlen_zero(), ast_test_flag, ast_verbose(), ast_waitfor_n(), ast_write(), ast_channel::call_forward, ast_channel::cdrflags, localuser::chan, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_name, ast_callerid::cid_num, ast_callerid::cid_rdnis, ast_channel::context, ast_frame::data, ast_frame::datalen, DIAL_NOFORWARDHTML, DIAL_STILLGOING, ast_channel::exten, localuser::forwards, 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, 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(), ast_channel::priority, result, senddialevent(), strdup, ast_frame::subclass, VERBOSE_PREFIX_2, and VERBOSE_PREFIX_3.

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


Variable Documentation

char* app = "Dial" [static]
 

Definition at line 61 of file app_dial.c.

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

char* descrip [static]
 

Definition at line 65 of file app_dial.c.

Referenced by load_module().

enum { ... } dial_exec_option_args
 

enum { ... } dial_exec_option_flags
 

LOCAL_USER_DECL
 

Definition at line 269 of file app_dial.c.

char* rapp = "RetryDial" [static]
 

Definition at line 173 of file app_dial.c.

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

char* rdescrip [static]
 

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

Referenced by load_module().

char* tdesc = "Dialing Application" [static]
 

Definition at line 59 of file app_dial.c.


Generated on Mon Mar 20 08:25:46 2006 for Asterisk - the Open Source PBX by  doxygen 1.3.9.1