Fri May 26 01:45:47 2006

Asterisk developer's documentation


app_dial.c File Reference

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

#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <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.

Data Structures

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

Defines

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

Enumerations

enum  {
  OPT_ANNOUNCE = (1 << 0), OPT_RESETCDR = (1 << 1), OPT_DTMF_EXIT = (1 << 2), OPT_SENDDTMF = (1 << 3),
  OPT_FORCECLID = (1 << 4), OPT_GO_ON = (1 << 5), OPT_CALLEE_HANGUP = (1 << 6), OPT_CALLER_HANGUP = (1 << 7),
  OPT_PRIORITY_JUMP = (1 << 8), OPT_DURATION_LIMIT = (1 << 9), OPT_MUSICBACK = (1 << 10), OPT_CALLEE_MACRO = (1 << 11),
  OPT_SCREEN_NOINTRO = (1 << 12), OPT_SCREEN_NOCLID = (1 << 13), OPT_ORIGINAL_CLID = (1 << 14), OPT_SCREENING = (1 << 15),
  OPT_PRIVACY = (1 << 16), OPT_RINGBACK = (1 << 17), OPT_DURATION_STOP = (1 << 18), OPT_CALLEE_TRANSFER = (1 << 19),
  OPT_CALLER_TRANSFER = (1 << 20), OPT_CALLEE_MONITOR = (1 << 21), OPT_CALLER_MONITOR = (1 << 22), OPT_GOTO = (1 << 23)
}
enum  {
  OPT_ARG_ANNOUNCE = 0, OPT_ARG_SENDDTMF, OPT_ARG_GOTO, OPT_ARG_DURATION_LIMIT,
  OPT_ARG_MUSICBACK, OPT_ARG_CALLEE_MACRO, OPT_ARG_PRIVACY, OPT_ARG_DURATION_STOP,
  OPT_ARG_ARRAY_SIZE
}

Functions

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

Variables

static char * app = "Dial"
static char * descrip
enum { ... }  dial_exec_option_args
struct {
   int   alarm
   char *   description
   unsigned int   event_log:1
   enum queue_result   id
   char *   name
   char *   name
   char *   name
   rtpPayloadType   payloadType
   unsigned int   queue_log:1
   char *   subtype
   char *   text
   char *   type
   int   val
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 286 of file app_dial.c.

Referenced by wait_for_answer().

#define AST_MAX_WATCHERS   256
 

Definition at line 288 of file app_dial.c.

Referenced by wait_for_answer().

#define DIAL_NOFORWARDHTML   (1 << 31)
 

Definition at line 217 of file app_dial.c.

Referenced by wait_for_answer().

#define DIAL_STILLGOING   (1 << 30)
 

Definition at line 216 of file app_dial.c.

Referenced by wait_for_answer().

#define HANDLE_CAUSE cause,
chan   ) 
 

Definition at line 290 of file app_dial.c.

Referenced by wait_for_answer().


Enumeration Type Documentation

anonymous enum
 

Enumerator:
OPT_ANNOUNCE 
OPT_RESETCDR 
OPT_DTMF_EXIT 
OPT_SENDDTMF 
OPT_FORCECLID 
OPT_GO_ON 
OPT_CALLEE_HANGUP 
OPT_CALLER_HANGUP 
OPT_PRIORITY_JUMP 
OPT_DURATION_LIMIT 
OPT_MUSICBACK 
OPT_CALLEE_MACRO 
OPT_SCREEN_NOINTRO 
OPT_SCREEN_NOCLID 
OPT_ORIGINAL_CLID 
OPT_SCREENING 
OPT_PRIVACY 
OPT_RINGBACK 
OPT_DURATION_STOP 
OPT_CALLEE_TRANSFER 
OPT_CALLER_TRANSFER 
OPT_CALLEE_MONITOR 
OPT_CALLER_MONITOR 
OPT_GOTO 

Definition at line 189 of file app_dial.c.

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

anonymous enum
 

Enumerator:
OPT_ARG_ANNOUNCE 
OPT_ARG_SENDDTMF 
OPT_ARG_GOTO 
OPT_ARG_DURATION_LIMIT 
OPT_ARG_MUSICBACK 
OPT_ARG_CALLEE_MACRO 
OPT_ARG_PRIVACY 
OPT_ARG_DURATION_STOP 
OPT_ARG_ARRAY_SIZE 

Definition at line 219 of file app_dial.c.

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

01751 {
01752    return tdesc;
01753 }

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

Definition at line 1615 of file app_dial.c.

References dial_exec_full().

Referenced by load_module().

01616 {
01617    struct ast_flags peerflags;
01618    memset(&peerflags, 0, sizeof(peerflags));
01619    return dial_exec_full(chan, data, &peerflags);
01620 }

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

Definition at line 725 of file app_dial.c.

References AST_APP_ARG, ast_app_parse_options(), ast_cdr_reset(), AST_DECLARE_APP_ARGS, ast_fileexists(), ast_goto_if_exists(), ast_log(), AST_MAX_EXTENSION, ast_play_and_record(), AST_PRIVACY_ALLOW, ast_privacy_check(), AST_PRIVACY_DENY, AST_PRIVACY_KILL, AST_PRIVACY_TORTURE, AST_PRIVACY_UNKNOWN, ast_shrink_phone_number(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_true(), ast_verbose(), ast_channel::cdr, ast_channel::cid, ast_callerid::cid_num, config, ast_channel::context, ast_bridge_config::end_sound, ast_channel::exten, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_WARNING, moh, ast_channel::name, OPT_ARG_ARRAY_SIZE, OPT_ARG_DURATION_LIMIT, OPT_ARG_DURATION_STOP, OPT_ARG_PRIVACY, OPT_ARG_SENDDTMF, OPT_DURATION_LIMIT, OPT_DURATION_STOP, OPT_PRIVACY, OPT_RESETCDR, OPT_SCREEN_NOCLID, OPT_SCREENING, OPT_SENDDTMF, option_verbose, parse(), pbx_builtin_getvar_helper(), peers, ast_bridge_config::play_warning, result, ast_bridge_config::start_sound, ast_bridge_config::start_time, strsep(), ast_bridge_config::timelimit, var, VERBOSE_PREFIX_3, ast_bridge_config::warning_freq, and ast_bridge_config::warning_sound.

Referenced by dial_exec(), and retrydial_exec().

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

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

Definition at line 335 of file app_dial.c.

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

Referenced by wait_for_answer().

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

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

Definition at line 272 of file app_dial.c.

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

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

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

References ASTERISK_GPL_KEY.

01763 {
01764    return ASTERISK_GPL_KEY;
01765 }

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

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

01741 {
01742    int res;
01743 
01744    res = ast_register_application(app, dial_exec, synopsis, descrip);
01745    res |= ast_register_application(rapp, retrydial_exec, rsynopsis, rdescrip);
01746    
01747    return res;
01748 }

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

Definition at line 316 of file app_dial.c.

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

Referenced by retrydial_exec(), and wait_for_answer().

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

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

Definition at line 1622 of file app_dial.c.

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

Referenced by load_module().

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

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

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

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

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

References ast_unregister_application(), and STANDARD_HANGUP_LOCALUSERS.

01729 {
01730    int res;
01731 
01732    res = ast_unregister_application(app);
01733    res |= ast_unregister_application(rapp);
01734 
01735    STANDARD_HANGUP_LOCALUSERS;
01736    
01737    return res;
01738 }

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

References STANDARD_USECOUNT.

01756 {
01757    int res;
01758    STANDARD_USECOUNT(res);
01759    return res;
01760 }

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

References ast_channel::accountcode, ast_call(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, AST_CAUSE_NORMAL_CLEARING, 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.

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


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

char* rapp = "RetryDial" [static]
 

Definition at line 174 of file app_dial.c.

char* rdescrip [static]
 

Definition at line 176 of file app_dial.c.

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

Definition at line 175 of file app_dial.c.

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 Fri May 26 01:45:48 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.6