Mon Nov 24 15:34:22 2008

Asterisk developer's documentation


app_dial.c File Reference

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

#include "asterisk.h"
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include "asterisk/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/rtp.h"
#include "asterisk/cdr.h"
#include "asterisk/manager.h"
#include "asterisk/privacy.h"
#include "asterisk/stringfields.h"
#include "asterisk/global_datastores.h"

Go to the source code of this file.

Data Structures

struct  dial_localuser

Defines

#define AST_MAX_WATCHERS   256
#define CAN_EARLY_BRIDGE(flags, chan, peer)
#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),
  OPT_OPERMODE = (1 << 24), OPT_CALLEE_PARK = (1 << 25), OPT_CALLER_PARK = (1 << 26), OPT_IGNORE_FORWARDING = (1 << 27)
}
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_OPERMODE, 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('i', OPT_IGNORE_FORWARDING), AST_APP_OPTION('j', OPT_PRIORITY_JUMP), AST_APP_OPTION('k', OPT_CALLEE_PARK), AST_APP_OPTION('K', OPT_CALLER_PARK), 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_ARG('O', OPT_OPERMODE, OPT_ARG_OPERMODE), 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),})
 AST_MODULE_INFO_STANDARD (ASTERISK_GPL_KEY,"Dialing Application")
static int dial_exec (struct ast_channel *chan, void *data)
static const char * get_cid_name (char *name, int namelen, struct ast_channel *chan)
static void hanguptree (struct dial_localuser *outgoing, struct ast_channel *exception)
static int load_module (void)
static int onedigit_goto (struct ast_channel *chan, const char *context, char exten, int pri)
static void replace_macro_delimiter (char *s)
static int retrydial_exec (struct ast_channel *chan, void *data)
static void senddialevent (struct ast_channel *src, struct ast_channel *dst)
static void set_dial_features (struct ast_flags *opts, struct ast_dial_features *features)
static int unload_module (void)
static int valid_priv_reply (struct ast_flags *opts, int res)
static struct ast_channelwait_for_answer (struct ast_channel *in, struct dial_localuser *outgoing, int *to, struct ast_flags *peerflags, int *sentringing, char *status, size_t statussize, int busystart, int nochanstart, int congestionstart, int priority_jump, int *result)

Variables

static char * app = "Dial"
static char * descrip
enum { ... }  dial_exec_option_args
enum { ... }  dial_exec_option_flags
static char * rapp = "RetryDial"
static char * rdescrip
static char * rsynopsis = "Place a call, retrying on failure allowing optional exit extension."
static char * synopsis = "Place a call and connect to the current channel"


Detailed Description

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

Author:
Mark Spencer <markster@digium.com>

Definition in file app_dial.c.


Define Documentation

#define AST_MAX_WATCHERS   256

Definition at line 331 of file app_dial.c.

#define CAN_EARLY_BRIDGE ( flags,
chan,
peer   ) 

Value:

Definition at line 301 of file app_dial.c.

Referenced by wait_for_answer().

#define DIAL_NOFORWARDHTML   (1 << 31)

Definition at line 254 of file app_dial.c.

Referenced by wait_for_answer().

#define DIAL_STILLGOING   (1 << 30)

Definition at line 253 of file app_dial.c.

Referenced by wait_for_answer().

#define HANDLE_CAUSE ( cause,
chan   ) 

Definition at line 333 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 
OPT_OPERMODE 
OPT_CALLEE_PARK 
OPT_CALLER_PARK 
OPT_IGNORE_FORWARDING 

Definition at line 222 of file app_dial.c.

00222      {
00223    OPT_ANNOUNCE =    (1 << 0),
00224    OPT_RESETCDR =    (1 << 1),
00225    OPT_DTMF_EXIT =      (1 << 2),
00226    OPT_SENDDTMF =    (1 << 3),
00227    OPT_FORCECLID =      (1 << 4),
00228    OPT_GO_ON =    (1 << 5),
00229    OPT_CALLEE_HANGUP =  (1 << 6),
00230    OPT_CALLER_HANGUP =  (1 << 7),
00231    OPT_PRIORITY_JUMP =  (1 << 8),
00232    OPT_DURATION_LIMIT = (1 << 9),
00233    OPT_MUSICBACK =      (1 << 10),
00234    OPT_CALLEE_MACRO =   (1 << 11),
00235    OPT_SCREEN_NOINTRO = (1 << 12),
00236    OPT_SCREEN_NOCLID =  (1 << 13),
00237    OPT_ORIGINAL_CLID =  (1 << 14),
00238    OPT_SCREENING =      (1 << 15),
00239    OPT_PRIVACY =     (1 << 16),
00240    OPT_RINGBACK =    (1 << 17),
00241    OPT_DURATION_STOP =  (1 << 18),
00242    OPT_CALLEE_TRANSFER =   (1 << 19),
00243    OPT_CALLER_TRANSFER =   (1 << 20),
00244    OPT_CALLEE_MONITOR = (1 << 21),
00245    OPT_CALLER_MONITOR = (1 << 22),
00246    OPT_GOTO =     (1 << 23),
00247    OPT_OPERMODE =       (1 << 24),
00248    OPT_CALLEE_PARK = (1 << 25),
00249    OPT_CALLER_PARK = (1 << 26),
00250    OPT_IGNORE_FORWARDING = (1 << 27),
00251 } 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_OPERMODE 
OPT_ARG_ARRAY_SIZE 

Definition at line 256 of file app_dial.c.

00256      {
00257    OPT_ARG_ANNOUNCE = 0,
00258    OPT_ARG_SENDDTMF,
00259    OPT_ARG_GOTO,
00260    OPT_ARG_DURATION_LIMIT,
00261    OPT_ARG_MUSICBACK,
00262    OPT_ARG_CALLEE_MACRO,
00263    OPT_ARG_PRIVACY,
00264    OPT_ARG_DURATION_STOP,
00265    OPT_ARG_OPERMODE,
00266    /* note: this entry _MUST_ be the last one in the enum */
00267    OPT_ARG_ARRAY_SIZE,
00268 } dial_exec_option_args;


Function Documentation

AST_APP_OPTIONS ( dial_exec_options   ) 

AST_MODULE_INFO_STANDARD ( ASTERISK_GPL_KEY  ,
"Dialing Application"   
)

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

Definition at line 1828 of file app_dial.c.

Referenced by load_module().

01829 {
01830    struct ast_flags peerflags;
01831 
01832    memset(&peerflags, 0, sizeof(peerflags));
01833 
01834    return dial_exec_full(chan, data, &peerflags, NULL);
01835 }

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

Definition at line 379 of file app_dial.c.

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

Referenced by wait_for_answer().

00380 {
00381    const char *context = S_OR(chan->macrocontext, chan->context);
00382    const char *exten = S_OR(chan->macroexten, chan->exten);
00383 
00384    return ast_get_hint(NULL, 0, name, namelen, chan, context, exten) ? name : "";
00385 }

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

Definition at line 317 of file app_dial.c.

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

00318 {
00319    /* Hang up a tree of stuff */
00320    struct dial_localuser *oo;
00321    while (outgoing) {
00322       /* Hangup any existing lines we have open */
00323       if (outgoing->chan && (outgoing->chan != exception))
00324          ast_hangup(outgoing->chan);
00325       oo = outgoing;
00326       outgoing=outgoing->next;
00327       free(oo);
00328    }
00329 }

static int load_module ( void   )  [static]

Definition at line 1965 of file app_dial.c.

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

01966 {
01967    int res;
01968 
01969    res = ast_register_application(app, dial_exec, synopsis, descrip);
01970    res |= ast_register_application(rapp, retrydial_exec, rsynopsis, rdescrip);
01971    
01972    return res;
01973 }

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

Definition at line 360 of file app_dial.c.

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

Referenced by retrydial_exec(), and wait_for_answer().

00361 {
00362    char rexten[2] = { exten, '\0' };
00363 
00364    if (context) {
00365       if (!ast_goto_if_exists(chan, context, rexten, pri))
00366          return 1;
00367    } else {
00368       if (!ast_goto_if_exists(chan, chan->context, rexten, pri))
00369          return 1;
00370       else if (!ast_strlen_zero(chan->macrocontext)) {
00371          if (!ast_goto_if_exists(chan, chan->macrocontext, rexten, pri))
00372             return 1;
00373       }
00374    }
00375    return 0;
00376 }

static void replace_macro_delimiter ( char *  s  )  [static]

Definition at line 778 of file app_dial.c.

00779 {
00780    for (; *s; s++)
00781       if (*s == '^')
00782          *s = '|';
00783 }

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

Definition at line 1837 of file app_dial.c.

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

Referenced by load_module().

01838 {
01839    char *announce = NULL, *dialdata = NULL;
01840    const char *context = NULL;
01841    int sleep = 0, loops = 0, res = -1;
01842    struct ast_module_user *u;
01843    struct ast_flags peerflags;
01844    
01845    if (ast_strlen_zero(data)) {
01846       ast_log(LOG_WARNING, "RetryDial requires an argument!\n");
01847       return -1;
01848    }  
01849 
01850    u = ast_module_user_add(chan);
01851 
01852    announce = ast_strdupa(data);
01853 
01854    memset(&peerflags, 0, sizeof(peerflags));
01855 
01856    if ((dialdata = strchr(announce, '|'))) {
01857       *dialdata++ = '\0';
01858       if (sscanf(dialdata, "%d", &sleep) == 1) {
01859          sleep *= 1000;
01860       } else {
01861          ast_log(LOG_ERROR, "%s requires the numerical argument <sleep>\n",rapp);
01862          goto done;
01863       }
01864       if ((dialdata = strchr(dialdata, '|'))) {
01865          *dialdata++ = '\0';
01866          if (sscanf(dialdata, "%d", &loops) != 1) {
01867             ast_log(LOG_ERROR, "%s requires the numerical argument <loops>\n",rapp);
01868             goto done;
01869          }
01870       }
01871    }
01872    
01873    if ((dialdata = strchr(dialdata, '|'))) {
01874       *dialdata++ = '\0';
01875    } else {
01876       ast_log(LOG_ERROR, "%s requires more arguments\n",rapp);
01877       goto done;
01878    }
01879       
01880    if (sleep < 1000)
01881       sleep = 10000;
01882 
01883    if (!loops)
01884       loops = -1; /* run forever */
01885    
01886    context = pbx_builtin_getvar_helper(chan, "EXITCONTEXT");
01887 
01888    res = 0;
01889    while (loops) {
01890       int continue_exec;
01891 
01892       chan->data = "Retrying";
01893       if (ast_test_flag(chan, AST_FLAG_MOH))
01894          ast_moh_stop(chan);
01895 
01896       res = dial_exec_full(chan, dialdata, &peerflags, &continue_exec);
01897       if (continue_exec)
01898          break;
01899 
01900       if (res == 0) {
01901          if (ast_test_flag(&peerflags, OPT_DTMF_EXIT)) {
01902             if (!ast_strlen_zero(announce)) {
01903                if (ast_fileexists(announce, NULL, chan->language) > 0) {
01904                   if(!(res = ast_streamfile(chan, announce, chan->language)))                      
01905                      ast_waitstream(chan, AST_DIGIT_ANY);
01906                } else
01907                   ast_log(LOG_WARNING, "Announce file \"%s\" specified in Retrydial does not exist\n", announce);
01908             }
01909             if (!res && sleep) {
01910                if (!ast_test_flag(chan, AST_FLAG_MOH))
01911                   ast_moh_start(chan, NULL, NULL);
01912                res = ast_waitfordigit(chan, sleep);
01913             }
01914          } else {
01915             if (!ast_strlen_zero(announce)) {
01916                if (ast_fileexists(announce, NULL, chan->language) > 0) {
01917                   if (!(res = ast_streamfile(chan, announce, chan->language)))
01918                      res = ast_waitstream(chan, "");
01919                } else
01920                   ast_log(LOG_WARNING, "Announce file \"%s\" specified in Retrydial does not exist\n", announce);
01921             }
01922             if (sleep) {
01923                if (!ast_test_flag(chan, AST_FLAG_MOH))
01924                   ast_moh_start(chan, NULL, NULL);
01925                if (!res)
01926                   res = ast_waitfordigit(chan, sleep);
01927             }
01928          }
01929       }
01930 
01931       if (res < 0)
01932          break;
01933       else if (res > 0) { /* Trying to send the call elsewhere (1 digit ext) */
01934          if (onedigit_goto(chan, context, (char) res, 1)) {
01935             res = 0;
01936             break;
01937          }
01938       }
01939       loops--;
01940    }
01941    if (loops == 0)
01942       res = 0;
01943    else if (res == 1)
01944       res = 0;
01945 
01946    if (ast_test_flag(chan, AST_FLAG_MOH))
01947       ast_moh_stop(chan);
01948  done:
01949    ast_module_user_remove(u);
01950    return res;
01951 }

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

Definition at line 387 of file app_dial.c.

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

Referenced by wait_for_answer().

00388 {
00389    /* XXX do we need also CallerIDnum ? */
00390    manager_event(EVENT_FLAG_CALL, "Dial", 
00391             "Source: %s\r\n"
00392             "Destination: %s\r\n"
00393             "CallerID: %s\r\n"
00394             "CallerIDName: %s\r\n"
00395             "SrcUniqueID: %s\r\n"
00396             "DestUniqueID: %s\r\n",
00397             src->name, dst->name, S_OR(src->cid.cid_num, "<unknown>"),
00398             S_OR(src->cid.cid_name, "<unknown>"), src->uniqueid,
00399             dst->uniqueid);
00400 }

static void set_dial_features ( struct ast_flags opts,
struct ast_dial_features features 
) [static]

Definition at line 798 of file app_dial.c.

References ast_app_options2str(), ast_copy_flags, AST_FEATURE_AUTOMON, AST_FEATURE_DISCONNECT, AST_FEATURE_PARKCALL, AST_FEATURE_REDIRECT, ast_set_flag, ast_test_flag, ast_dial_features::features_callee, ast_dial_features::features_caller, ast_flags::flags, OPT_CALLEE_HANGUP, OPT_CALLEE_MONITOR, OPT_CALLEE_PARK, OPT_CALLEE_TRANSFER, OPT_CALLER_HANGUP, OPT_CALLER_MONITOR, OPT_CALLER_PARK, OPT_CALLER_TRANSFER, and ast_dial_features::options.

00799 {
00800    struct ast_flags perm_opts = {.flags = 0};
00801 
00802    ast_copy_flags(&perm_opts, opts,
00803       OPT_CALLER_TRANSFER | OPT_CALLER_PARK | OPT_CALLER_MONITOR | OPT_CALLER_HANGUP |
00804       OPT_CALLEE_TRANSFER | OPT_CALLEE_PARK | OPT_CALLEE_MONITOR | OPT_CALLEE_HANGUP);
00805 
00806    memset(features->options, 0, sizeof(features->options));
00807 
00808    ast_app_options2str(dial_exec_options, &perm_opts, features->options, sizeof(features->options));
00809    if (ast_test_flag(&perm_opts, OPT_CALLEE_TRANSFER))
00810       ast_set_flag(&(features->features_callee), AST_FEATURE_REDIRECT);
00811    if (ast_test_flag(&perm_opts, OPT_CALLER_TRANSFER))
00812       ast_set_flag(&(features->features_caller), AST_FEATURE_REDIRECT);
00813    if (ast_test_flag(&perm_opts, OPT_CALLEE_HANGUP))
00814       ast_set_flag(&(features->features_callee), AST_FEATURE_DISCONNECT);
00815    if (ast_test_flag(&perm_opts, OPT_CALLER_HANGUP))
00816       ast_set_flag(&(features->features_caller), AST_FEATURE_DISCONNECT);
00817    if (ast_test_flag(&perm_opts, OPT_CALLEE_MONITOR))
00818       ast_set_flag(&(features->features_callee), AST_FEATURE_AUTOMON);
00819    if (ast_test_flag(&perm_opts, OPT_CALLER_MONITOR))
00820       ast_set_flag(&(features->features_caller), AST_FEATURE_AUTOMON);
00821    if (ast_test_flag(&perm_opts, OPT_CALLEE_PARK))
00822       ast_set_flag(&(features->features_callee), AST_FEATURE_PARKCALL);
00823    if (ast_test_flag(&perm_opts, OPT_CALLER_PARK))
00824       ast_set_flag(&(features->features_caller), AST_FEATURE_PARKCALL);
00825 }

static int unload_module ( void   )  [static]

Definition at line 1953 of file app_dial.c.

References ast_module_user_hangup_all, and ast_unregister_application().

01954 {
01955    int res;
01956 
01957    res = ast_unregister_application(app);
01958    res |= ast_unregister_application(rapp);
01959 
01960    ast_module_user_hangup_all();
01961    
01962    return res;
01963 }

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

Definition at line 787 of file app_dial.c.

References ast_test_flag, OPT_PRIVACY, and OPT_SCREENING.

00788 {
00789    if (res < '1')
00790       return 0;
00791    if (ast_test_flag(opts, OPT_PRIVACY) && res <= '5')
00792       return 1;
00793    if (ast_test_flag(opts, OPT_SCREENING) && res <= '4')
00794       return 1;
00795    return 0;
00796 }

static struct ast_channel* wait_for_answer ( struct ast_channel in,
struct dial_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 402 of file app_dial.c.

References ast_channel::_state, accountcode, ast_cdr::answer, ast_call(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, AST_CAUSE_NORMAL_CLEARING, AST_CDR_ANSWERED, ast_cdr_noanswer(), ast_channel_datastore_inherit(), ast_channel_inherit_variables(), ast_channel_make_compatible(), ast_channel_sendhtml(), ast_check_hangup(), 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_SRCUPDATE, AST_CONTROL_UNHOLD, AST_CONTROL_VIDUPDATE, ast_copy_flags, ast_deactivate_generator(), AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_HTML, AST_FRAME_IMAGE, AST_FRAME_TEXT, AST_FRAME_VOICE, ast_frfree, ast_goto_if_exists(), ast_hangup(), ast_indicate(), ast_indicate_data(), ast_log(), AST_MAX_EXTENSION, AST_MAX_WATCHERS, ast_opt_priority_jumping, ast_read(), ast_request(), ast_rtp_early_bridge(), ast_rtp_make_compatible(), ast_set_callerid(), AST_STATE_UP, ast_strdup, ast_string_field_set, ast_strlen_zero(), ast_test_flag, ast_verbose(), ast_waitfor_n(), ast_write(), CAN_EARLY_BRIDGE, ast_channel::cdr, ast_channel::cdrflags, dial_localuser::chan, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_name, ast_callerid::cid_num, context, ast_channel::context, DIAL_NOFORWARDHTML, DIAL_STILLGOING, ast_channel::dialcontext, ast_cdr::disposition, ast_channel::exten, f, free, get_cid_name(), HANDLE_CAUSE, ast_channel::hangupcause, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, ast_channel::macroexten, ast_channel::nativeformats, dial_localuser::next, onedigit_goto(), OPT_CALLEE_HANGUP, OPT_CALLEE_MONITOR, OPT_CALLEE_PARK, OPT_CALLEE_TRANSFER, OPT_CALLER_HANGUP, OPT_CALLER_MONITOR, OPT_CALLER_PARK, OPT_CALLER_TRANSFER, OPT_DTMF_EXIT, OPT_FORCECLID, OPT_IGNORE_FORWARDING, OPT_MUSICBACK, OPT_ORIGINAL_CLID, OPT_RINGBACK, option_debug, option_verbose, pbx_builtin_getvar_helper(), S_OR, senddialevent(), ast_channel::tech, VERBOSE_PREFIX_2, and VERBOSE_PREFIX_3.

Referenced by try_calling().

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


Variable Documentation

char* app = "Dial" [static]

Definition at line 71 of file app_dial.c.

char* descrip [static]

Definition at line 75 of file app_dial.c.

enum { ... } dial_exec_option_args

enum { ... } dial_exec_option_flags

char* rapp = "RetryDial" [static]

Definition at line 207 of file app_dial.c.

char* rdescrip [static]

Definition at line 209 of file app_dial.c.

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

Definition at line 208 of file app_dial.c.

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

Definition at line 73 of file app_dial.c.


Generated on Mon Nov 24 15:34:22 2008 for Asterisk - the Open Source PBX by  doxygen 1.4.7