1999-12-04 21:35:07 +00:00
/*
2005-09-14 20:46:50 +00:00
* Asterisk - - An open source telephony toolkit .
1999-12-04 21:35:07 +00:00
*
2005-01-21 07:06:25 +00:00
* Copyright ( C ) 1999 - 2005 , Digium , Inc .
1999-12-04 21:35:07 +00:00
*
2004-09-22 05:19:06 +00:00
* Mark Spencer < markster @ digium . com >
1999-12-04 21:35:07 +00:00
*
2005-09-14 20:46:50 +00:00
* See http : //www.asterisk.org for more information about
* the Asterisk project . Please do not directly contact
* any of the maintainers of this project for assistance ;
* the project provides a web site , mailing lists and IRC
* channels for your use .
*
1999-12-04 21:35:07 +00:00
* This program is free software , distributed under the terms of
2005-09-14 20:46:50 +00:00
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree .
*/
2005-10-24 20:12:06 +00:00
/*! \file
2005-09-14 20:46:50 +00:00
*
2005-10-24 20:12:06 +00:00
* \ brief dial ( ) & retrydial ( ) - Trivial application to dial a channel and send an URL on answer
2005-09-14 20:46:50 +00:00
*
2005-11-06 15:09:47 +00:00
* \ ingroup applications
1999-12-04 21:35:07 +00:00
*/
2005-06-06 22:39:32 +00:00
# include <stdlib.h>
# include <errno.h>
# include <unistd.h>
# include <string.h>
# include <stdlib.h>
# include <stdio.h>
# include <sys/time.h>
# include <sys/signal.h>
# include <netinet/in.h>
# include "asterisk.h"
ASTERISK_FILE_VERSION ( __FILE__ , " $Revision$ " )
2005-04-21 06:02:45 +00:00
# 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"
2005-07-12 03:23:31 +00:00
# include "asterisk/privacy.h"
1999-12-04 21:35:07 +00:00
2001-12-20 15:21:47 +00:00
static char * tdesc = " Dialing Application " ;
1999-12-04 21:35:07 +00:00
static char * app = " Dial " ;
2003-11-06 04:08:40 +00:00
static char * synopsis = " Place a call and connect to the current channel " ;
2001-05-07 03:15:48 +00:00
static char * descrip =
2005-11-11 13:34:38 +00:00
" Dial(Technology/resource[&Tech2/resource2...][|timeout][|options][|URL]): \n "
" This applicaiton will place calls to one or more specified channels. As soon \n "
" as one of the requested channels answers, the originating channel will be \n "
" answered, if it has not already been answered. These two channels will then \n "
" be active in a bridged call. All other channels that were requested will then \n "
" be hung up. \n "
" Unless there is a timeout specified, the Dial application will wait \n "
" indefinitely until one of the called channels answers, the user hangs up, or \n "
" if all of the called channels are busy or unavailable. Dialplan executing will \n "
2005-11-11 15:52:55 +00:00
" continue if no requested channels can be called, or if the timeout expires. \n \n "
2005-11-11 13:34:38 +00:00
" This application sets the following channel variables upon completion: \n "
" DIALEDTIME - This is the time from dialing a channel until when it \n "
" answers. \n "
" ANSWEREDTIME - This is the amount of time for actual call. \n "
" DIALSTATUS - This is the status of the call: \n "
" CHANUNAVAIL | CONGESTION | NOANSWER | BUSY | ANSWER | CANCEL \n "
" DONTCALL | TORTURE \n "
" For the Privacy and Screening Modes, the DIALSTATUS variable will be set to \n "
" DONTCALL if the called party chooses to send the calling party to the 'Go Away' \n "
" script. The DIALSTATUS variable will be set to TORTURE if the called party \n "
" wants to send the caller to the 'torture' script. \n "
" This application will report normal termination if the originating channel \n "
" hangs up, or if the call is bridged and either of the parties in the bridge \n "
" ends the call. \n "
2004-07-19 19:47:21 +00:00
" The optional URL will be sent to the called party if the channel supports it. \n "
2004-11-07 21:49:43 +00:00
" If the OUTBOUND_GROUP variable is set, all peer channels created by this \n "
2005-11-11 15:52:55 +00:00
" application will be put into that group (as in Set(GROUP()=...). \n \n "
2005-11-11 13:34:38 +00:00
" Options: \n "
" A(x) - Play an announcement to the called party, using 'x' as the file. \n "
" C - Reset the CDR for this call. \n "
" d - Allow the calling user to dial a 1 digit extension while waiting for \n "
" a call to be answered. Exit to that extension if it exists in the \n "
" current context, or the context defined in the EXITCONTEXT variable, \n "
" if it exists. \n "
" D([called][:calling]) - Send the specified DTMF strings *after* the called \n "
" party has answered, but before the call gets bridged. The 'called' \n "
" DTMF string is sent to the called party, and the 'calling' DTMF \n "
" string is sent to the calling party. Both parameters can be used \n "
" alone. \n "
" f - Force the callerid of the *calling* channel to be set as the \n "
" extension associated with the channel using a dialplan 'hint'. \n "
" For example, some PSTNs do not allow CallerID to be set to anything \n "
" other than the number assigned to the caller. \n "
" g - Proceed with dialplan execution at the current extension if the \n "
" destination channel hangs up. \n "
" G(context^exten^pri) - If the call is answered, transfer both parties to \n "
" the specified priority. Optionally, an extension, or extension and \n "
" context may be specified. Otherwise, the current extension is used. \n "
" h - Allow the called party to hang up by sending the '*' DTMF digit. \n "
" H - Allow the calling party to hang up by hitting the '*' DTMF digit. \n "
" j - Jump to priority n+101 if all of the requested channels were busy. \n "
" L(x[:y][:z]) - Limit the call to 'x' ms. Play a warning when 'y' ms are \n "
" left. Repeat the warning every 'z' ms. The following special \n "
" variables can be used with this option: \n "
" * LIMIT_PLAYAUDIO_CALLER yes|no (default yes) \n "
" Play sounds to the caller. \n "
" * LIMIT_PLAYAUDIO_CALLEE yes|no \n "
" Play sounds to the callee. \n "
" * LIMIT_TIMEOUT_FILE File to play when time is up. \n "
" * LIMIT_CONNECT_FILE File to play when call begins. \n "
" * LIMIT_WARNING_FILE File to play as warning if 'y' is defined. \n "
" The default is to say the time remaining. \n "
" m([class]) - Provide hold music to the calling party until a requested \n "
" channel answers. A specific MusicOnHold class can be \n "
" specified. \n "
" M(x[^arg]) - Execute the Macro for the *called* channel before connecting \n "
" to the calling channel. Arguments can be specified to the Macro \n "
" using '^' as a delimeter. The Macro can set the variable \n "
" MACRO_RESULT to specify the following actions after the Macro is \n "
" finished executing. \n "
" * ABORT Hangup both legs of the call. \n "
" * CONGESTION Behave as if line congestion was encountered. \n "
" * BUSY Behave as if a busy signal was encountered. This will also \n "
" have the application jump to priority n+101 if the \n "
" 'j' option is set. \n "
" * CONTINUE Hangup the called party and allow the calling party \n "
" to continue dialplan execution at the next priority. \n "
" * GOTO:<context>^<exten>^<priority> - Transfer the call to the \n "
" specified priority. Optionally, an extension, or \n "
" extension and priority can be specified. \n "
" n - This option is a modifier for the screen/privacy mode. It specifies \n "
" that no introductions are to be saved in the priv-callerintros \n "
" directory. \n "
" N - This option is a modifier for the screen/privacy mode. It specifies \n "
" that if callerID is present, do not screen the call. \n "
" o - Specify that the CallerID that was present on the *calling* channel \n "
" be set as the CallerID on the *called* channel. This was the \n "
" behavior of Asterisk 1.0 and earlier. \n "
" p - This option enables screening mode. This is basically Privacy mode \n "
" without memory. \n "
" P([x]) - Enable privacy mode. Use 'x' as the family/key in the database if \n "
" it is provided. The current extension is used if a database \n "
" family/key is not specified. \n "
" r - Indicate ringing to the calling party. Pass no audio to the calling \n "
" party until the called channel has answered. \n "
" S(x) - Hang up the call after 'x' seconds *after* the called party has \n "
" answered the call. \n "
" t - Allow the called party to transfer the calling party by sending the \n "
" DTMF sequence defiend in features.conf. \n "
" T - Allow the calling party to transfer the called party by sending the \n "
" DTMF sequence defined in features.conf. \n "
" w - Allow the called party to enable recording of the call by sending \n "
" the DTMF sequence defined for one-touch recording in features.conf. \n "
" W - Allow the calling party to enable recording of the call by sending \n "
" the DTMF sequence defined for one-touch recording in features.conf. \n " ;
2001-05-07 03:15:48 +00:00
2005-01-18 03:12:53 +00:00
/* RetryDial App by Anthony Minessale II <anthmct@yahoo.com> Jan/2005 */
static char * rapp = " RetryDial " ;
2005-04-27 01:50:53 +00:00
static char * rsynopsis = " Place a call, retrying on failure allowing optional exit extension. " ;
2005-01-18 03:12:53 +00:00
static char * rdescrip =
2005-11-11 13:34:38 +00:00
" RetryDial(announce|sleep|retries|dialargs): This application will attempt to \n "
" place a call using the normal Dial application. If no channel can be reached, \n "
2005-11-14 10:24:59 +00:00
" the 'announce' file will be played. Then, it will wait 'sleep' number of \n "
2005-11-11 13:34:38 +00:00
" seconds before retying the call. After 'retires' number of attempts, the \n "
" calling channel will continue at the next priority in the dialplan. If the \n "
" 'retries' setting is set to 0, this application will retry endlessly. \n "
" While waiting to retry a call, a 1 digit extension may be dialed. If that \n "
" extension exists in either the context defined in ${EXITCONTEXT} or the current \n "
" one, The call will jump to that extension immediately. \n "
" The 'dialargs' are specified in the same format that arguments are provided \n "
" to the Dial application. \n " ;
2005-01-18 03:12:53 +00:00
2005-11-03 21:40:36 +00:00
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 ) ,
} dial_exec_option_flags ;
# define DIAL_STILLGOING (1 << 30)
# define DIAL_NOFORWARDHTML (1 << 31)
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 ,
/* note: this entry _MUST_ be the last one in the enum */
OPT_ARG_ARRAY_SIZE ,
} dial_exec_option_args ;
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 ) ,
} ) ;
/* We define a custom "local user" structure because we
1999-12-04 21:35:07 +00:00
use it not only for keeping track of what is in use but
also for keeping track of who we ' re dialing . */
struct localuser {
struct ast_channel * chan ;
2005-01-05 23:05:49 +00:00
unsigned int flags ;
2004-11-28 22:08:44 +00:00
int forwards ;
1999-12-04 21:35:07 +00:00
struct localuser * next ;
} ;
LOCAL_USER_DECL ;
static void hanguptree ( struct localuser * outgoing , struct ast_channel * exception )
{
/* Hang up a tree of stuff */
struct localuser * oo ;
2005-01-18 03:12:53 +00:00
while ( outgoing ) {
1999-12-04 21:35:07 +00:00
/* Hangup any existing lines we have open */
2003-04-06 06:37:08 +00:00
if ( outgoing - > chan & & ( outgoing - > chan ! = exception ) )
1999-12-04 21:35:07 +00:00
ast_hangup ( outgoing - > chan ) ;
oo = outgoing ;
outgoing = outgoing - > next ;
free ( oo ) ;
}
}
2004-11-28 22:08:44 +00:00
# define AST_MAX_FORWARDS 8
2004-06-22 17:42:14 +00:00
# define AST_MAX_WATCHERS 256
2001-05-07 03:15:48 +00:00
2004-12-12 04:58:07 +00:00
# define HANDLE_CAUSE(cause, chan) do { \
2004-10-26 22:25:43 +00:00
switch ( cause ) { \
case AST_CAUSE_BUSY : \
2004-12-12 04:58:07 +00:00
if ( chan - > cdr ) \
ast_cdr_busy ( chan - > cdr ) ; \
2004-10-26 22:25:43 +00:00
numbusy + + ; \
2004-11-21 20:38:32 +00:00
break ; \
2004-10-26 22:25:43 +00:00
case AST_CAUSE_CONGESTION : \
2004-12-12 04:58:07 +00:00
if ( chan - > cdr ) \
2005-11-08 01:05:52 +00:00
ast_cdr_failed ( chan - > cdr ) ; \
2004-10-26 22:25:43 +00:00
numcongestion + + ; \
2004-11-21 20:38:32 +00:00
break ; \
2005-05-16 00:09:09 +00:00
case AST_CAUSE_UNREGISTERED : \
if ( chan - > cdr ) \
2005-11-08 01:05:52 +00:00
ast_cdr_failed ( chan - > cdr ) ; \
2005-05-16 00:09:09 +00:00
numnochan + + ; \
break ; \
2004-10-26 22:25:43 +00:00
default : \
numnochan + + ; \
2004-11-21 20:38:32 +00:00
break ; \
2004-10-26 22:25:43 +00:00
} \
2005-01-18 03:12:53 +00:00
} while ( 0 )
2005-04-29 15:04:26 +00:00
static int onedigit_goto ( struct ast_channel * chan , char * context , char exten , int pri )
2005-01-18 03:12:53 +00:00
{
2005-04-29 15:04:26 +00:00
char rexten [ 2 ] = { exten , ' \0 ' } ;
2005-01-18 03:12:53 +00:00
if ( context ) {
2005-06-01 18:02:46 +00:00
if ( ! ast_goto_if_exists ( chan , context , rexten , pri ) )
2005-01-18 03:12:53 +00:00
return 1 ;
} else {
2005-06-01 18:02:46 +00:00
if ( ! ast_goto_if_exists ( chan , chan - > context , rexten , pri ) )
2005-01-18 03:12:53 +00:00
return 1 ;
2005-04-29 15:04:26 +00:00
else if ( ! ast_strlen_zero ( chan - > macrocontext ) ) {
2005-06-01 18:02:46 +00:00
if ( ! ast_goto_if_exists ( chan , chan - > macrocontext , rexten , pri ) )
2005-01-18 03:12:53 +00:00
return 1 ;
}
}
return 0 ;
}
2004-10-26 22:25:43 +00:00
2005-02-01 01:53:25 +00:00
static char * get_cid_name ( char * name , int namelen , struct ast_channel * chan )
{
char * context ;
char * exten ;
if ( ! ast_strlen_zero ( chan - > macrocontext ) )
context = chan - > macrocontext ;
else
context = chan - > context ;
if ( ! ast_strlen_zero ( chan - > macroexten ) )
exten = chan - > macroexten ;
else
exten = chan - > exten ;
if ( ast_get_hint ( NULL , 0 , name , namelen , chan , context , exten ) )
return name ;
else
return " " ;
}
2005-02-07 15:19:34 +00:00
static void senddialevent ( struct ast_channel * src , struct ast_channel * dst )
{
manager_event ( EVENT_FLAG_CALL , " Dial " ,
2005-04-13 16:43:26 +00:00
" Source: %s \r \n "
" Destination: %s \r \n "
" CallerID: %s \r \n "
" CallerIDName: %s \r \n "
" SrcUniqueID: %s \r \n "
" DestUniqueID: %s \r \n " ,
src - > name , dst - > name , src - > cid . cid_num ? src - > cid . cid_num : " <unknown> " ,
src - > cid . cid_name ? src - > cid . cid_name : " <unknown> " , src - > uniqueid ,
dst - > uniqueid ) ;
2005-02-07 15:19:34 +00:00
}
2005-07-26 16:29:56 +00:00
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 )
1999-12-04 21:35:07 +00:00
{
struct localuser * o ;
int found ;
int numlines ;
2004-10-26 22:25:43 +00:00
int numbusy = busystart ;
int numcongestion = congestionstart ;
int numnochan = nochanstart ;
2004-11-21 20:38:32 +00:00
int prestart = busystart + congestionstart + nochanstart ;
2004-10-26 22:25:43 +00:00
int cause ;
1999-12-04 21:35:07 +00:00
int orig = * to ;
struct ast_frame * f ;
struct ast_channel * peer = NULL ;
2004-06-22 17:42:14 +00:00
struct ast_channel * watchers [ AST_MAX_WATCHERS ] ;
2001-05-07 03:15:48 +00:00
int pos ;
int single ;
struct ast_channel * winner ;
2005-01-18 03:12:53 +00:00
char * context = NULL ;
2005-02-01 01:53:25 +00:00
char cidname [ AST_MAX_EXTENSION ] ;
2005-01-18 03:12:53 +00:00
2005-11-03 21:40:36 +00:00
single = ( outgoing & & ! outgoing - > next & & ! ast_test_flag ( outgoing , OPT_MUSICBACK | OPT_RINGBACK ) ) ;
2001-05-07 03:15:48 +00:00
if ( single ) {
2003-11-05 20:53:49 +00:00
/* Turn off hold music, etc */
2004-07-07 16:02:13 +00:00
ast_deactivate_generator ( in ) ;
2001-05-07 03:15:48 +00:00
/* If we are calling a single channel, make them compatible for in-band tone purpose */
ast_channel_make_compatible ( outgoing - > chan , in ) ;
}
2002-05-17 14:33:10 +00:00
2005-01-18 03:12:53 +00:00
while ( * to & & ! peer ) {
1999-12-04 21:35:07 +00:00
o = outgoing ;
found = - 1 ;
2001-05-07 03:15:48 +00:00
pos = 1 ;
2004-11-21 20:38:32 +00:00
numlines = prestart ;
2001-05-07 03:15:48 +00:00
watchers [ 0 ] = in ;
2005-01-18 03:12:53 +00:00
while ( o ) {
2001-05-07 03:15:48 +00:00
/* Keep track of important channels */
2005-01-05 23:05:49 +00:00
if ( ast_test_flag ( o , DIAL_STILLGOING ) & & o - > chan ) {
2001-05-07 03:15:48 +00:00
watchers [ pos + + ] = o - > chan ;
found = 1 ;
1999-12-04 21:35:07 +00:00
}
o = o - > next ;
2001-05-07 03:15:48 +00:00
numlines + + ;
1999-12-04 21:35:07 +00:00
}
2001-05-07 03:15:48 +00:00
if ( found < 0 ) {
2004-06-23 03:16:58 +00:00
if ( numlines = = ( numbusy + numcongestion + numnochan ) ) {
1999-12-04 21:35:07 +00:00
if ( option_verbose > 2 )
2004-12-12 04:58:07 +00:00
ast_verbose ( VERBOSE_PREFIX_2 " Everyone is busy/congested at this time (%d:%d/%d/%d) \n " , numlines , numbusy , numcongestion , numnochan ) ;
2004-06-23 03:16:58 +00:00
if ( numbusy )
2005-07-07 23:32:37 +00:00
strcpy ( status , " BUSY " ) ;
2004-06-23 03:16:58 +00:00
else if ( numcongestion )
2005-07-07 23:32:37 +00:00
strcpy ( status , " CONGESTION " ) ;
2004-06-23 03:16:58 +00:00
else if ( numnochan )
2005-07-07 23:32:37 +00:00
strcpy ( status , " CHANUNAVAIL " ) ;
2005-07-26 16:29:56 +00:00
if ( option_priority_jumping | | priority_jump )
ast_goto_if_exists ( in , in - > context , in - > exten , in - > priority + 101 ) ;
1999-12-04 21:35:07 +00:00
} else {
if ( option_verbose > 2 )
2004-12-12 04:58:07 +00:00
ast_verbose ( VERBOSE_PREFIX_2 " No one is available to answer at this time (%d:%d/%d/%d) \n " , numlines , numbusy , numcongestion , numnochan ) ;
1999-12-04 21:35:07 +00:00
}
2001-05-07 03:15:48 +00:00
* to = 0 ;
1999-12-04 21:35:07 +00:00
return NULL ;
}
2001-05-07 03:15:48 +00:00
winner = ast_waitfor_n ( watchers , pos , to ) ;
1999-12-04 21:35:07 +00:00
o = outgoing ;
2005-01-18 03:12:53 +00:00
while ( o ) {
2005-01-05 23:05:49 +00:00
if ( ast_test_flag ( o , DIAL_STILLGOING ) & & o - > chan & & ( o - > chan - > _state = = AST_STATE_UP ) ) {
2002-09-02 15:20:28 +00:00
if ( ! peer ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " %s answered %s \n " , o - > chan - > name , in - > name ) ;
peer = o - > chan ;
2005-11-12 01:33:10 +00:00
ast_copy_flags ( peerflags , o ,
OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
DIAL_NOFORWARDHTML ) ;
2002-09-02 15:20:28 +00:00
}
2003-07-25 15:32:02 +00:00
} else if ( o - > chan & & ( o - > chan = = winner ) ) {
2004-05-04 19:11:25 +00:00
if ( ! ast_strlen_zero ( o - > chan - > call_forward ) ) {
2005-09-07 21:01:31 +00:00
char tmpchan [ 256 ] ;
2004-06-21 06:11:56 +00:00
char * stuff ;
char * tech ;
2005-07-07 23:32:37 +00:00
ast_copy_string ( tmpchan , o - > chan - > call_forward , sizeof ( tmpchan ) ) ;
2004-06-21 06:11:56 +00:00
if ( ( stuff = strchr ( tmpchan , ' / ' ) ) ) {
* stuff = ' \0 ' ;
stuff + + ;
tech = tmpchan ;
} else {
snprintf ( tmpchan , sizeof ( tmpchan ) , " %s@%s " , o - > chan - > call_forward , o - > chan - > context ) ;
stuff = tmpchan ;
tech = " Local " ;
}
2003-03-27 16:02:10 +00:00
/* Before processing channel, go ahead and check for forwarding */
2004-11-28 22:08:44 +00:00
o - > forwards + + ;
if ( o - > forwards < AST_MAX_FORWARDS ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Now forwarding %s to '%s/%s' (thanks to %s) \n " , in - > name , tech , stuff , o - > chan - > name ) ;
/* Setup parameters */
o - > chan = ast_request ( tech , in - > nativeformats , stuff , & cause ) ;
if ( ! o - > chan )
ast_log ( LOG_NOTICE , " Unable to create local channel for call forward to '%s/%s' (cause = %d) \n " , tech , stuff , cause ) ;
} else {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Too many forwards from %s \n " , o - > chan - > name ) ;
cause = AST_CAUSE_CONGESTION ;
o - > chan = NULL ;
}
2003-04-06 06:37:08 +00:00
if ( ! o - > chan ) {
2005-01-05 23:05:49 +00:00
ast_clear_flag ( o , DIAL_STILLGOING ) ;
2004-10-26 22:25:43 +00:00
HANDLE_CAUSE ( cause , in ) ;
2004-01-15 23:32:27 +00:00
} else {
2004-10-02 00:58:31 +00:00
if ( o - > chan - > cid . cid_num )
free ( o - > chan - > cid . cid_num ) ;
o - > chan - > cid . cid_num = NULL ;
if ( o - > chan - > cid . cid_name )
free ( o - > chan - > cid . cid_name ) ;
o - > chan - > cid . cid_name = NULL ;
2004-06-14 19:43:41 +00:00
2005-11-03 21:40:36 +00:00
if ( ast_test_flag ( o , OPT_FORCECLID ) ) {
2004-06-14 19:43:41 +00:00
char * newcid = NULL ;
2005-10-26 19:48:14 +00:00
if ( ! ast_strlen_zero ( in - > macroexten ) )
2004-06-14 19:43:41 +00:00
newcid = in - > macroexten ;
2004-02-27 04:24:42 +00:00
else
2004-06-14 19:43:41 +00:00
newcid = in - > exten ;
2004-10-02 00:58:31 +00:00
o - > chan - > cid . cid_num = strdup ( newcid ) ;
2005-07-07 23:32:37 +00:00
ast_copy_string ( o - > chan - > accountcode , winner - > accountcode , sizeof ( o - > chan - > accountcode ) ) ;
2004-07-12 14:46:10 +00:00
o - > chan - > cdrflags = winner - > cdrflags ;
2004-10-02 00:58:31 +00:00
if ( ! o - > chan - > cid . cid_num )
2004-06-14 19:43:41 +00:00
ast_log ( LOG_WARNING , " Out of memory \n " ) ;
} else {
2004-10-02 00:58:31 +00:00
if ( in - > cid . cid_num ) {
o - > chan - > cid . cid_num = strdup ( in - > cid . cid_num ) ;
if ( ! o - > chan - > cid . cid_num )
ast_log ( LOG_WARNING , " Out of memory \n " ) ;
}
if ( in - > cid . cid_name ) {
o - > chan - > cid . cid_name = strdup ( in - > cid . cid_name ) ;
if ( ! o - > chan - > cid . cid_name )
2004-08-27 03:16:16 +00:00
ast_log ( LOG_WARNING , " Out of memory \n " ) ;
}
2005-07-07 23:32:37 +00:00
ast_copy_string ( o - > chan - > accountcode , in - > accountcode , sizeof ( o - > chan - > accountcode ) ) ;
2004-07-12 14:46:10 +00:00
o - > chan - > cdrflags = in - > cdrflags ;
2004-01-15 23:32:27 +00:00
}
2004-06-14 19:43:41 +00:00
2004-10-02 00:58:31 +00:00
if ( in - > cid . cid_ani ) {
if ( o - > chan - > cid . cid_ani )
free ( o - > chan - > cid . cid_ani ) ;
o - > chan - > cid . cid_ani = malloc ( strlen ( in - > cid . cid_ani ) + 1 ) ;
if ( o - > chan - > cid . cid_ani )
2005-07-07 23:32:37 +00:00
ast_copy_string ( o - > chan - > cid . cid_ani , in - > cid . cid_ani , sizeof ( o - > chan - > cid . cid_ani ) ) ;
2004-02-27 04:24:42 +00:00
else
ast_log ( LOG_WARNING , " Out of memory \n " ) ;
2004-01-15 23:32:27 +00:00
}
2004-10-02 00:58:31 +00:00
if ( o - > chan - > cid . cid_rdnis )
free ( o - > chan - > cid . cid_rdnis ) ;
2004-05-04 19:11:25 +00:00
if ( ! ast_strlen_zero ( in - > macroexten ) )
2004-10-02 00:58:31 +00:00
o - > chan - > cid . cid_rdnis = strdup ( in - > macroexten ) ;
2004-03-18 20:02:15 +00:00
else
2004-10-02 00:58:31 +00:00
o - > chan - > cid . cid_rdnis = strdup ( in - > exten ) ;
2004-01-15 23:32:27 +00:00
if ( ast_call ( o - > chan , tmpchan , 0 ) ) {
ast_log ( LOG_NOTICE , " Failed to dial on local channel for call forward to '%s' \n " , tmpchan ) ;
2005-01-05 23:05:49 +00:00
ast_clear_flag ( o , DIAL_STILLGOING ) ;
2004-01-15 23:32:27 +00:00
ast_hangup ( o - > chan ) ;
o - > chan = NULL ;
2004-06-23 03:16:58 +00:00
numnochan + + ;
2005-01-16 07:58:51 +00:00
} else {
2005-02-07 15:19:34 +00:00
senddialevent ( in , o - > chan ) ;
2005-01-16 07:58:51 +00:00
/* After calling, set callerid to extension */
2005-11-03 21:40:36 +00:00
if ( ! ast_test_flag ( peerflags , OPT_ORIGINAL_CLID ) )
2005-02-02 20:35:25 +00:00
ast_set_callerid ( o - > chan , ast_strlen_zero ( in - > macroexten ) ? in - > exten : in - > macroexten , get_cid_name ( cidname , sizeof ( cidname ) , in ) , NULL ) ;
2004-01-15 23:32:27 +00:00
}
2003-04-06 06:37:08 +00:00
}
2004-07-12 14:46:10 +00:00
/* Hangup the original channel now, in case we needed it */
ast_hangup ( winner ) ;
2003-04-06 06:37:08 +00:00
continue ;
2003-03-27 16:02:10 +00:00
}
2001-05-07 03:15:48 +00:00
f = ast_read ( winner ) ;
if ( f ) {
if ( f - > frametype = = AST_FRAME_CONTROL ) {
switch ( f - > subclass ) {
2005-09-07 19:13:00 +00:00
case AST_CONTROL_ANSWER :
2001-05-07 03:15:48 +00:00
/* This is our guy if someone answered. */
if ( ! peer ) {
1999-12-04 21:35:07 +00:00
if ( option_verbose > 2 )
2001-05-07 03:15:48 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " %s answered %s \n " , o - > chan - > name , in - > name ) ;
peer = o - > chan ;
2005-11-12 01:33:10 +00:00
ast_copy_flags ( peerflags , o ,
OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
DIAL_NOFORWARDHTML ) ;
1999-12-04 21:35:07 +00:00
}
2004-12-28 23:18:31 +00:00
/* If call has been answered, then the eventual hangup is likely to be normal hangup */
in - > hangupcause = AST_CAUSE_NORMAL_CLEARING ;
o - > chan - > hangupcause = AST_CAUSE_NORMAL_CLEARING ;
2001-05-07 03:15:48 +00:00
break ;
case AST_CONTROL_BUSY :
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " %s is busy \n " , o - > chan - > name ) ;
2003-10-01 16:05:40 +00:00
in - > hangupcause = o - > chan - > hangupcause ;
2003-07-22 23:08:45 +00:00
ast_hangup ( o - > chan ) ;
2003-07-22 15:16:55 +00:00
o - > chan = NULL ;
2005-01-05 23:05:49 +00:00
ast_clear_flag ( o , DIAL_STILLGOING ) ;
2004-10-26 22:25:43 +00:00
HANDLE_CAUSE ( AST_CAUSE_BUSY , in ) ;
2001-05-07 03:15:48 +00:00
break ;
2001-10-15 17:39:25 +00:00
case AST_CONTROL_CONGESTION :
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " %s is circuit-busy \n " , o - > chan - > name ) ;
2003-10-01 16:05:40 +00:00
in - > hangupcause = o - > chan - > hangupcause ;
2003-07-22 23:08:45 +00:00
ast_hangup ( o - > chan ) ;
2003-07-22 15:16:55 +00:00
o - > chan = NULL ;
2005-01-05 23:05:49 +00:00
ast_clear_flag ( o , DIAL_STILLGOING ) ;
2004-10-26 22:25:43 +00:00
HANDLE_CAUSE ( AST_CAUSE_CONGESTION , in ) ;
2001-10-15 17:39:25 +00:00
break ;
2001-05-07 03:15:48 +00:00
case AST_CONTROL_RINGING :
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " %s is ringing \n " , o - > chan - > name ) ;
2005-11-03 21:40:36 +00:00
if ( ! ( * sentringing ) & & ! ast_test_flag ( outgoing , OPT_MUSICBACK ) ) {
2001-05-07 03:15:48 +00:00
ast_indicate ( in , AST_CONTROL_RINGING ) ;
2004-07-08 09:20:14 +00:00
( * sentringing ) + + ;
2001-05-07 03:15:48 +00:00
}
break ;
2003-05-12 19:25:20 +00:00
case AST_CONTROL_PROGRESS :
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " %s is making progress passing it to %s \n " , o - > chan - > name , in - > name ) ;
2005-11-03 21:40:36 +00:00
if ( ! ast_test_flag ( outgoing , OPT_RINGBACK ) )
2004-10-07 18:28:49 +00:00
ast_indicate ( in , AST_CONTROL_PROGRESS ) ;
2003-05-12 19:25:20 +00:00
break ;
2005-08-30 02:12:09 +00:00
case AST_CONTROL_VIDUPDATE :
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " %s requested a video update, passing it to %s \n " , o - > chan - > name , in - > name ) ;
ast_indicate ( in , AST_CONTROL_VIDUPDATE ) ;
break ;
2005-07-10 16:05:59 +00:00
case AST_CONTROL_PROCEEDING :
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " %s is proceeding passing it to %s \n " , o - > chan - > name , in - > name ) ;
2005-11-03 21:40:36 +00:00
if ( ! ast_test_flag ( outgoing , OPT_RINGBACK ) )
2005-07-10 16:05:59 +00:00
ast_indicate ( in , AST_CONTROL_PROCEEDING ) ;
break ;
2005-01-17 12:37:55 +00:00
case AST_CONTROL_HOLD :
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Call on %s placed on hold \n " , o - > chan - > name ) ;
ast_indicate ( in , AST_CONTROL_HOLD ) ;
break ;
case AST_CONTROL_UNHOLD :
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Call on %s left from hold \n " , o - > chan - > name ) ;
ast_indicate ( in , AST_CONTROL_UNHOLD ) ;
break ;
2001-05-07 03:15:48 +00:00
case AST_CONTROL_OFFHOOK :
2004-11-03 22:37:55 +00:00
case AST_CONTROL_FLASH :
/* Ignore going off hook and flash */
2001-05-07 03:15:48 +00:00
break ;
2003-04-06 06:11:25 +00:00
case - 1 :
2005-11-03 21:40:36 +00:00
if ( ! ast_test_flag ( outgoing , OPT_RINGBACK | OPT_MUSICBACK ) ) {
2004-03-19 00:08:43 +00:00
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " %s stopped sounds \n " , o - > chan - > name ) ;
ast_indicate ( in , - 1 ) ;
2004-07-08 09:20:14 +00:00
( * sentringing ) = 0 ;
2004-03-19 00:08:43 +00:00
}
2003-04-06 06:11:25 +00:00
break ;
2001-05-07 03:15:48 +00:00
default :
ast_log ( LOG_DEBUG , " Dunno what to do with control type %d \n " , f - > subclass ) ;
1999-12-04 21:35:07 +00:00
}
2002-05-17 14:33:10 +00:00
} else if ( single & & ( f - > frametype = = AST_FRAME_VOICE ) & &
2005-11-03 21:40:36 +00:00
! ( ast_test_flag ( outgoing , OPT_RINGBACK | OPT_MUSICBACK ) ) ) {
2001-05-07 03:15:48 +00:00
if ( ast_write ( in , f ) )
2005-07-08 19:10:39 +00:00
ast_log ( LOG_DEBUG , " Unable to forward frame \n " ) ;
2002-05-17 14:33:10 +00:00
} else if ( single & & ( f - > frametype = = AST_FRAME_IMAGE ) & &
2005-11-03 21:40:36 +00:00
! ( ast_test_flag ( outgoing , OPT_RINGBACK | OPT_MUSICBACK ) ) ) {
2001-10-15 17:39:25 +00:00
if ( ast_write ( in , f ) )
2005-07-08 19:10:39 +00:00
ast_log ( LOG_DEBUG , " Unable to forward image \n " ) ;
2005-04-09 18:54:58 +00:00
} else if ( single & & ( f - > frametype = = AST_FRAME_TEXT ) & &
2005-11-03 21:40:36 +00:00
! ( ast_test_flag ( outgoing , OPT_RINGBACK | OPT_MUSICBACK ) ) ) {
2005-04-09 18:54:58 +00:00
if ( ast_write ( in , f ) )
2005-07-08 19:10:39 +00:00
ast_log ( LOG_DEBUG , " Unable to text \n " ) ;
2005-02-28 06:06:42 +00:00
} else if ( single & & ( f - > frametype = = AST_FRAME_HTML ) & & ! ast_test_flag ( outgoing , DIAL_NOFORWARDHTML ) )
ast_channel_sendhtml ( in , f - > subclass , f - > data , f - > datalen ) ;
2001-05-07 03:15:48 +00:00
ast_frfree ( f ) ;
} else {
2003-10-01 16:05:40 +00:00
in - > hangupcause = o - > chan - > hangupcause ;
2003-07-22 23:08:45 +00:00
ast_hangup ( o - > chan ) ;
2003-07-22 15:16:55 +00:00
o - > chan = NULL ;
2005-01-05 23:05:49 +00:00
ast_clear_flag ( o , DIAL_STILLGOING ) ;
1999-12-04 21:35:07 +00:00
}
}
o = o - > next ;
}
2001-05-07 03:15:48 +00:00
if ( winner = = in ) {
1999-12-04 21:35:07 +00:00
f = ast_read ( in ) ;
#if 0
if ( f & & ( f - > frametype ! = AST_FRAME_VOICE ) )
2005-09-07 19:13:00 +00:00
printf ( " Frame type: %d, %d \n " , f - > frametype , f - > subclass ) ;
2001-10-15 17:39:25 +00:00
else if ( ! f | | ( f - > frametype ! = AST_FRAME_VOICE ) )
printf ( " Hangup received on %s \n " , in - > name ) ;
1999-12-04 21:35:07 +00:00
# endif
2001-10-15 17:39:25 +00:00
if ( ! f | | ( ( f - > frametype = = AST_FRAME_CONTROL ) & & ( f - > subclass = = AST_CONTROL_HANGUP ) ) ) {
1999-12-04 21:35:07 +00:00
/* Got hung up */
* to = - 1 ;
2005-07-07 23:32:37 +00:00
strcpy ( status , " CANCEL " ) ;
2004-12-06 17:12:21 +00:00
if ( f )
ast_frfree ( f ) ;
1999-12-04 21:35:07 +00:00
return NULL ;
}
2005-01-18 03:12:53 +00:00
if ( f & & ( f - > frametype = = AST_FRAME_DTMF ) ) {
2005-11-03 21:40:36 +00:00
if ( ast_test_flag ( peerflags , OPT_DTMF_EXIT ) ) {
2005-01-18 03:12:53 +00:00
context = pbx_builtin_getvar_helper ( in , " EXITCONTEXT " ) ;
2005-04-29 15:04:26 +00:00
if ( onedigit_goto ( in , context , ( char ) f - > subclass , 1 ) ) {
2005-01-18 03:12:53 +00:00
if ( option_verbose > 3 )
ast_verbose ( VERBOSE_PREFIX_3 " User hit %c to disconnect call. \n " , f - > subclass ) ;
* to = 0 ;
* result = f - > subclass ;
strcpy ( status , " CANCEL " ) ;
ast_frfree ( f ) ;
return NULL ;
}
}
2005-11-03 21:40:36 +00:00
if ( ast_test_flag ( peerflags , OPT_CALLER_HANGUP ) & &
2005-01-18 03:12:53 +00:00
( f - > subclass = = ' * ' ) ) { /* hmm it it not guarenteed to be '*' anymore. */
if ( option_verbose > 3 )
ast_verbose ( VERBOSE_PREFIX_3 " User hit %c to disconnect call. \n " , f - > subclass ) ;
* to = 0 ;
strcpy ( status , " CANCEL " ) ;
ast_frfree ( f ) ;
return NULL ;
}
2002-09-02 15:20:28 +00:00
}
2005-01-18 03:12:53 +00:00
2005-02-28 06:06:42 +00:00
/* Forward HTML stuff */
if ( single & & f & & ( f - > frametype = = AST_FRAME_HTML ) & & ! ast_test_flag ( outgoing , DIAL_NOFORWARDHTML ) )
ast_channel_sendhtml ( outgoing - > chan , f - > subclass , f - > data , f - > datalen ) ;
2002-09-02 15:20:28 +00:00
if ( single & & ( ( f - > frametype = = AST_FRAME_VOICE ) | | ( f - > frametype = = AST_FRAME_DTMF ) ) ) {
if ( ast_write ( outgoing - > chan , f ) )
ast_log ( LOG_WARNING , " Unable to forward voice \n " ) ;
}
2005-08-30 02:12:09 +00:00
if ( single & & ( f - > frametype = = AST_FRAME_CONTROL ) & & ( f - > subclass = = AST_CONTROL_VIDUPDATE ) ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " %s requested a video update, passing it to %s \n " , in - > name , outgoing - > chan - > name ) ;
ast_indicate ( outgoing - > chan , AST_CONTROL_VIDUPDATE ) ;
}
2005-08-03 20:17:53 +00:00
ast_frfree ( f ) ;
1999-12-04 21:35:07 +00:00
}
2001-05-07 03:15:48 +00:00
if ( ! * to & & ( option_verbose > 2 ) )
ast_verbose ( VERBOSE_PREFIX_3 " Nobody picked up in %d ms \n " , orig ) ;
1999-12-04 21:35:07 +00:00
}
2002-05-17 14:33:10 +00:00
1999-12-04 21:35:07 +00:00
return peer ;
2001-05-07 03:15:48 +00:00
1999-12-04 21:35:07 +00:00
}
2005-01-18 03:12:53 +00:00
static int dial_exec_full ( struct ast_channel * chan , void * data , struct ast_flags * peerflags )
1999-12-04 21:35:07 +00:00
{
int res = - 1 ;
struct localuser * u ;
2005-11-02 21:50:03 +00:00
char * tech , * number , * rest , * cur ;
2005-09-07 21:01:31 +00:00
char privcid [ 256 ] ;
2005-07-12 03:23:31 +00:00
char privintro [ 1024 ] ;
2004-06-21 13:30:58 +00:00
struct localuser * outgoing = NULL , * tmp ;
struct ast_channel * peer ;
1999-12-04 21:35:07 +00:00
int to ;
2004-10-26 22:25:43 +00:00
int numbusy = 0 ;
int numcongestion = 0 ;
int numnochan = 0 ;
int cause ;
1999-12-18 07:01:48 +00:00
char numsubst [ AST_MAX_EXTENSION ] ;
1999-12-25 00:46:58 +00:00
char restofit [ AST_MAX_EXTENSION ] ;
2005-02-01 01:53:25 +00:00
char cidname [ AST_MAX_EXTENSION ] ;
1999-12-18 07:01:48 +00:00
char * newnum ;
2004-10-02 00:58:31 +00:00
char * l ;
2005-07-12 03:23:31 +00:00
int privdb_val = 0 ;
2004-03-06 00:02:40 +00:00
unsigned int calldurationlimit = 0 ;
2004-04-26 23:22:34 +00:00
struct ast_bridge_config config ;
long timelimit = 0 ;
long play_warning = 0 ;
long warning_freq = 0 ;
char * warning_sound = NULL ;
char * end_sound = NULL ;
char * start_sound = NULL ;
2005-04-11 02:46:25 +00:00
char * dtmfcalled = NULL , * dtmfcalling = NULL ;
2005-11-02 21:46:52 +00:00
char * var ;
2005-09-07 21:01:31 +00:00
char status [ 256 ] ;
2004-04-26 23:22:34 +00:00
int play_to_caller = 0 , play_to_callee = 0 ;
2005-11-02 21:46:52 +00:00
int sentringing = 0 , moh = 0 ;
2004-11-07 21:49:43 +00:00
char * outbound_group = NULL ;
2004-11-22 22:11:10 +00:00
char * macro_result = NULL , * macro_transfer_dest = NULL ;
2005-01-18 03:12:53 +00:00
int digit = 0 , result = 0 ;
2004-07-14 01:10:24 +00:00
time_t start_time , answer_time , end_time ;
2004-11-22 22:11:10 +00:00
struct ast_app * app = NULL ;
2005-11-02 21:46:52 +00:00
char * parse ;
AST_DECLARE_APP_ARGS ( args ,
AST_APP_ARG ( peers ) ;
AST_APP_ARG ( timeout ) ;
AST_APP_ARG ( options ) ;
AST_APP_ARG ( url ) ;
) ;
struct ast_flags opts = { 0 , } ;
char * opt_args [ OPT_ARG_ARRAY_SIZE ] ;
2005-03-17 22:39:04 +00:00
2005-10-26 19:48:14 +00:00
if ( ast_strlen_zero ( data ) ) {
2005-11-02 21:46:52 +00:00
ast_log ( LOG_WARNING , " Dial requires an argument (technology/number) \n " ) ;
1999-12-04 21:35:07 +00:00
return - 1 ;
}
2004-09-22 05:19:06 +00:00
2005-10-19 18:19:02 +00:00
LOCAL_USER_ADD ( u ) ;
2005-11-02 21:46:52 +00:00
if ( ! ( parse = ast_strdupa ( data ) ) ) {
ast_log ( LOG_WARNING , " Memory allocation failure \n " ) ;
2005-10-19 18:19:02 +00:00
LOCAL_USER_REMOVE ( u ) ;
2004-09-22 05:19:06 +00:00
return - 1 ;
}
1999-12-04 21:35:07 +00:00
2005-11-02 21:46:52 +00:00
AST_STANDARD_APP_ARGS ( args , parse ) ;
if ( ! ast_strlen_zero ( args . options ) ) {
2005-11-03 21:19:11 +00:00
if ( ast_app_parse_options ( dial_exec_options , & opts , opt_args , args . options ) ) {
2005-11-02 21:46:52 +00:00
LOCAL_USER_REMOVE ( u ) ;
return - 1 ;
2001-03-30 18:47:35 +00:00
}
1999-12-04 21:35:07 +00:00
}
2003-01-17 05:10:52 +00:00
2005-11-02 21:46:52 +00:00
if ( ast_strlen_zero ( args . peers ) ) {
ast_log ( LOG_WARNING , " Dial requires an argument (technology/number) \n " ) ;
LOCAL_USER_REMOVE ( u ) ;
return - 1 ;
}
2004-04-26 23:22:34 +00:00
2005-11-02 21:46:52 +00:00
if ( ast_test_flag ( & opts , OPT_DURATION_STOP ) & & ! ast_strlen_zero ( opt_args [ OPT_ARG_DURATION_STOP ] ) ) {
calldurationlimit = atoi ( opt_args [ OPT_ARG_DURATION_STOP ] ) ;
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Setting call duration limit to %d seconds. \n " , calldurationlimit ) ;
}
2005-03-17 22:39:04 +00:00
2005-11-02 21:46:52 +00:00
if ( ast_test_flag ( & opts , OPT_SENDDTMF ) & & ! ast_strlen_zero ( opt_args [ OPT_ARG_SENDDTMF ] ) ) {
parse = opt_args [ OPT_ARG_SENDDTMF ] ;
dtmfcalled = strsep ( & parse , " : " ) ;
dtmfcalling = parse ;
}
2005-03-17 22:39:04 +00:00
2005-11-02 21:46:52 +00:00
if ( ast_test_flag ( & opts , OPT_DURATION_LIMIT ) & & ! ast_strlen_zero ( opt_args [ OPT_ARG_DURATION_LIMIT ] ) ) {
char * limit_str , * warning_str , * warnfreq_str ;
parse = opt_args [ OPT_ARG_DURATION_LIMIT ] ;
limit_str = strsep ( & parse , " : " ) ;
warning_str = strsep ( & parse , " : " ) ;
warnfreq_str = parse ;
timelimit = atol ( limit_str ) ;
if ( warning_str )
play_warning = atol ( warning_str ) ;
if ( warnfreq_str )
warning_freq = atol ( warnfreq_str ) ;
if ( ! timelimit ) {
timelimit = play_to_caller = play_to_callee = play_warning = warning_freq = 0 ;
warning_sound = NULL ;
2005-06-02 17:12:04 +00:00
}
2005-11-02 21:46:52 +00:00
var = pbx_builtin_getvar_helper ( chan , " LIMIT_PLAYAUDIO_CALLER " ) ;
play_to_caller = var ? ast_true ( var ) : 1 ;
var = pbx_builtin_getvar_helper ( chan , " LIMIT_PLAYAUDIO_CALLEE " ) ;
play_to_callee = var ? ast_true ( var ) : 0 ;
if ( ! play_to_caller & & ! play_to_callee )
play_to_caller = 1 ;
var = pbx_builtin_getvar_helper ( chan , " LIMIT_WARNING_FILE " ) ;
warning_sound = var ? var : " timeleft " ;
var = pbx_builtin_getvar_helper ( chan , " LIMIT_TIMEOUT_FILE " ) ;
end_sound = var ? var : NULL ;
var = pbx_builtin_getvar_helper ( chan , " LIMIT_CONNECT_FILE " ) ;
start_sound = var ? var : NULL ;
/* undo effect of S(x) in case they are both used */
calldurationlimit = 0 ;
/* more efficient do it like S(x) does since no advanced opts*/
if ( ! play_warning & & ! start_sound & & ! end_sound & & timelimit ) {
calldurationlimit = timelimit / 1000 ;
timelimit = play_to_caller = play_to_callee = play_warning = warning_freq = 0 ;
} else if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " Limit Data for this call: \n " ) ;
ast_verbose ( VERBOSE_PREFIX_3 " - timelimit = %ld \n " , timelimit ) ;
ast_verbose ( VERBOSE_PREFIX_3 " - play_warning = %ld \n " , play_warning ) ;
ast_verbose ( VERBOSE_PREFIX_3 " - play_to_caller= %s \n " , play_to_caller ? " yes " : " no " ) ;
ast_verbose ( VERBOSE_PREFIX_3 " - play_to_callee= %s \n " , play_to_callee ? " yes " : " no " ) ;
ast_verbose ( VERBOSE_PREFIX_3 " - warning_freq = %ld \n " , warning_freq ) ;
ast_verbose ( VERBOSE_PREFIX_3 " - start_sound = %s \n " , start_sound ? start_sound : " UNDEF " ) ;
ast_verbose ( VERBOSE_PREFIX_3 " - warning_sound = %s \n " , warning_sound ? warning_sound : " UNDEF " ) ;
ast_verbose ( VERBOSE_PREFIX_3 " - end_sound = %s \n " , end_sound ? end_sound : " UNDEF " ) ;
2005-07-12 03:23:31 +00:00
}
2003-01-17 05:10:52 +00:00
}
2005-11-02 21:46:52 +00:00
if ( ast_test_flag ( & opts , OPT_RESETCDR ) & & chan - > cdr )
2005-11-06 21:00:35 +00:00
ast_cdr_reset ( chan - > cdr , NULL ) ;
2005-11-02 21:46:52 +00:00
if ( ast_test_flag ( & opts , OPT_PRIVACY ) & & ast_strlen_zero ( opt_args [ OPT_ARG_PRIVACY ] ) )
opt_args [ OPT_ARG_PRIVACY ] = ast_strdupa ( chan - > exten ) ;
if ( ast_test_flag ( & opts , OPT_PRIVACY ) | | ast_test_flag ( & opts , OPT_SCREENING ) ) {
2005-07-12 03:23:31 +00:00
char callerid [ 60 ] ;
2004-10-02 00:58:31 +00:00
l = chan - > cid . cid_num ;
2005-10-26 19:48:14 +00:00
if ( ! ast_strlen_zero ( l ) ) {
2005-07-12 03:23:31 +00:00
ast_shrink_phone_number ( l ) ;
2005-11-02 21:46:52 +00:00
if ( ast_test_flag ( & opts , OPT_PRIVACY ) ) {
2005-07-12 03:23:31 +00:00
if ( option_verbose > 2 )
2005-11-02 21:46:52 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " Privacy DB is '%s', clid is '%s' \n " ,
opt_args [ OPT_ARG_PRIVACY ] , l ) ;
privdb_val = ast_privacy_check ( opt_args [ OPT_ARG_PRIVACY ] , l ) ;
2005-07-12 03:23:31 +00:00
}
else {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Privacy Screening, clid is '%s' \n " , l ) ;
privdb_val = AST_PRIVACY_UNKNOWN ;
}
} else {
char * tnam , * tn2 ;
tnam = ast_strdupa ( chan - > name ) ;
/* clean the channel name so slashes don't try to end up in disk file name */
for ( tn2 = tnam ; * tn2 ; tn2 + + ) {
if ( * tn2 = = ' / ' )
* tn2 = ' = ' ; /* any other chars to be afraid of? */
}
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Privacy-- callerid is empty \n " ) ;
snprintf ( callerid , sizeof ( callerid ) , " NOCALLERID_%s%s " , chan - > exten , tnam ) ;
l = callerid ;
privdb_val = AST_PRIVACY_UNKNOWN ;
}
ast_copy_string ( privcid , l , sizeof ( privcid ) ) ;
2005-11-02 21:46:52 +00:00
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 */
2005-07-12 03:23:31 +00:00
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " CallerID set (%s); N option set; Screening should be off \n " , privcid ) ;
privdb_val = AST_PRIVACY_ALLOW ;
}
2005-11-02 21:46:52 +00:00
else if ( ast_test_flag ( & opts , OPT_SCREEN_NOCLID ) & & strncmp ( privcid , " NOCALLERID " , 10 ) = = 0 ) {
2005-07-12 03:23:31 +00:00
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " CallerID blank; N option set; Screening should happen; dbval is %d \n " , privdb_val ) ;
}
if ( privdb_val = = AST_PRIVACY_DENY ) {
ast_verbose ( VERBOSE_PREFIX_3 " Privacy DB reports PRIVACY_DENY for this callerid. Dial reports unavailable \n " ) ;
res = 0 ;
goto out ;
}
else if ( privdb_val = = AST_PRIVACY_KILL ) {
2005-09-07 19:13:00 +00:00
ast_goto_if_exists ( chan , chan - > context , chan - > exten , chan - > priority + 201 ) ;
2005-07-12 03:23:31 +00:00
res = 0 ;
goto out ; /* Is this right? */
}
else if ( privdb_val = = AST_PRIVACY_TORTURE ) {
2005-09-07 19:13:00 +00:00
ast_goto_if_exists ( chan , chan - > context , chan - > exten , chan - > priority + 301 ) ;
2005-07-12 03:23:31 +00:00
res = 0 ;
goto out ; /* is this right??? */
}
else if ( privdb_val = = AST_PRIVACY_UNKNOWN ) {
/* Get the user's intro, store it in priv-callerintros/$CID,
unless it is already there - - this should be done before the
call is actually dialed */
/* make sure the priv-callerintros dir exists? */
snprintf ( privintro , sizeof ( privintro ) , " priv-callerintros/%s " , privcid ) ;
if ( ast_fileexists ( privintro , NULL , NULL ) > 0 & & strncmp ( privcid , " NOCALLERID " , 10 ) ! = 0 ) {
/* the DELUX version of this code would allow this caller the
option to hear and retape their previously recorded intro .
*/
}
else {
int duration ; /* for feedback from play_and_wait */
/* the file doesn't exist yet. Let the caller submit his
vocal intro for posterity */
/* priv-recordintro script:
" At the tone, please say your name: "
*/
ast_play_and_record ( chan , " priv-recordintro " , privintro , 4 , " gsm " , & duration , 128 , 2000 , 0 ) ; /* NOTE: I've reduced the total time to 4 sec */
/* don't think we'll need a lock removed, we took care of
conflicts by naming the privintro file */
}
}
2003-01-17 05:10:52 +00:00
}
2004-11-07 21:49:43 +00:00
/* If a channel group has been specified, get it for use when we create peer channels */
outbound_group = pbx_builtin_getvar_helper ( chan , " OUTBOUND_GROUP " ) ;
2005-11-12 01:33:10 +00:00
ast_copy_flags ( peerflags , & opts , OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID ) ;
2005-11-02 21:50:03 +00:00
cur = args . peers ;
1999-12-04 21:35:07 +00:00
do {
/* Remember where to start next time */
2001-03-30 18:47:35 +00:00
rest = strchr ( cur , ' & ' ) ;
if ( rest ) {
* rest = 0 ;
rest + + ;
}
1999-12-18 07:01:48 +00:00
/* Get a technology/[device:]number pair */
2001-03-30 18:47:35 +00:00
tech = cur ;
number = strchr ( tech , ' / ' ) ;
1999-12-04 21:35:07 +00:00
if ( ! number ) {
2005-11-02 21:46:52 +00:00
ast_log ( LOG_WARNING , " Dial argument takes format (technology/[device:]number1) \n " ) ;
1999-12-04 21:35:07 +00:00
goto out ;
}
2001-03-30 18:47:35 +00:00
* number = ' \0 ' ;
number + + ;
1999-12-04 21:35:07 +00:00
tmp = malloc ( sizeof ( struct localuser ) ) ;
if ( ! tmp ) {
ast_log ( LOG_WARNING , " Out of memory \n " ) ;
goto out ;
}
2002-05-17 14:33:10 +00:00
memset ( tmp , 0 , sizeof ( struct localuser ) ) ;
2005-11-02 21:46:52 +00:00
if ( opts . flags ) {
2005-11-03 21:40:36 +00:00
ast_copy_flags ( tmp , & opts ,
OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID ) ;
2005-11-02 21:46:52 +00:00
ast_set2_flag ( tmp , args . url , DIAL_NOFORWARDHTML ) ;
2002-05-17 14:33:10 +00:00
}
2005-07-07 23:32:37 +00:00
ast_copy_string ( numsubst , number , sizeof ( numsubst ) ) ;
1999-12-04 21:35:07 +00:00
/* If we're dialing by extension, look at the extension to know what to dial */
1999-12-18 07:01:48 +00:00
if ( ( newnum = strstr ( numsubst , " BYEXTENSION " ) ) ) {
2005-07-07 23:32:37 +00:00
/* strlen("BYEXTENSION") == 11 */
ast_copy_string ( restofit , newnum + 11 , sizeof ( restofit ) ) ;
1999-12-25 00:46:58 +00:00
snprintf ( newnum , sizeof ( numsubst ) - ( newnum - numsubst ) , " %s%s " , chan - > exten , restofit ) ;
1999-12-18 07:01:48 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Dialing by extension %s \n " , numsubst ) ;
1999-12-04 21:35:07 +00:00
}
/* Request the peer */
2004-10-26 22:25:43 +00:00
tmp - > chan = ast_request ( tech , chan - > nativeformats , numsubst , & cause ) ;
1999-12-04 21:35:07 +00:00
if ( ! tmp - > chan ) {
/* If we can't, just go on to the next call */
2005-07-05 17:16:17 +00:00
ast_log ( LOG_NOTICE , " Unable to create channel of type '%s' (cause %d - %s) \n " , tech , cause , ast_cause2str ( cause ) ) ;
2004-10-26 22:25:43 +00:00
HANDLE_CAUSE ( cause , chan ) ;
2004-10-28 14:25:50 +00:00
cur = rest ;
2005-10-05 21:18:28 +00:00
if ( ! cur )
chan - > hangupcause = cause ;
1999-12-04 21:35:07 +00:00
continue ;
}
2005-01-27 16:33:12 +00:00
pbx_builtin_setvar_helper ( tmp - > chan , " DIALEDPEERNUMBER " , numsubst ) ;
2004-05-04 19:11:25 +00:00
if ( ! ast_strlen_zero ( tmp - > chan - > call_forward ) ) {
2005-09-07 21:01:31 +00:00
char tmpchan [ 256 ] ;
2004-06-21 06:11:56 +00:00
char * stuff ;
char * tech ;
2005-07-07 23:32:37 +00:00
ast_copy_string ( tmpchan , tmp - > chan - > call_forward , sizeof ( tmpchan ) ) ;
2004-06-21 06:11:56 +00:00
if ( ( stuff = strchr ( tmpchan , ' / ' ) ) ) {
* stuff = ' \0 ' ;
stuff + + ;
tech = tmpchan ;
} else {
snprintf ( tmpchan , sizeof ( tmpchan ) , " %s@%s " , tmp - > chan - > call_forward , tmp - > chan - > context ) ;
stuff = tmpchan ;
tech = " Local " ;
}
2004-11-28 22:08:44 +00:00
tmp - > forwards + + ;
if ( tmp - > forwards < AST_MAX_FORWARDS ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Now forwarding %s to '%s/%s' (thanks to %s) \n " , chan - > name , tech , stuff , tmp - > chan - > name ) ;
ast_hangup ( tmp - > chan ) ;
/* Setup parameters */
tmp - > chan = ast_request ( tech , chan - > nativeformats , stuff , & cause ) ;
if ( ! tmp - > chan )
ast_log ( LOG_NOTICE , " Unable to create local channel for call forward to '%s/%s' (cause = %d) \n " , tech , stuff , cause ) ;
} else {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Too many forwards from %s \n " , tmp - > chan - > name ) ;
ast_hangup ( tmp - > chan ) ;
tmp - > chan = NULL ;
cause = AST_CAUSE_CONGESTION ;
}
2003-04-06 06:37:08 +00:00
if ( ! tmp - > chan ) {
2004-10-26 22:25:43 +00:00
HANDLE_CAUSE ( cause , chan ) ;
2004-10-28 14:25:50 +00:00
cur = rest ;
2003-04-06 06:37:08 +00:00
continue ;
}
2002-03-05 15:59:01 +00:00
}
2004-11-01 02:23:28 +00:00
2005-01-08 17:23:29 +00:00
/* Inherit specially named variables from parent channel */
ast_channel_inherit_variables ( chan , tmp - > chan ) ;
2004-11-01 02:23:28 +00:00
1999-12-18 07:01:48 +00:00
tmp - > chan - > appl = " AppDial " ;
tmp - > chan - > data = " (Outgoing Line) " ;
2001-12-20 15:21:47 +00:00
tmp - > chan - > whentohangup = 0 ;
2004-10-02 00:58:31 +00:00
if ( tmp - > chan - > cid . cid_num )
free ( tmp - > chan - > cid . cid_num ) ;
tmp - > chan - > cid . cid_num = NULL ;
if ( tmp - > chan - > cid . cid_name )
free ( tmp - > chan - > cid . cid_name ) ;
tmp - > chan - > cid . cid_name = NULL ;
if ( tmp - > chan - > cid . cid_ani )
free ( tmp - > chan - > cid . cid_ani ) ;
tmp - > chan - > cid . cid_ani = NULL ;
if ( chan - > cid . cid_num )
tmp - > chan - > cid . cid_num = strdup ( chan - > cid . cid_num ) ;
if ( chan - > cid . cid_name )
tmp - > chan - > cid . cid_name = strdup ( chan - > cid . cid_name ) ;
if ( chan - > cid . cid_ani )
tmp - > chan - > cid . cid_ani = strdup ( chan - > cid . cid_ani ) ;
2003-12-04 22:26:38 +00:00
/* Copy language from incoming to outgoing */
2005-07-07 23:32:37 +00:00
ast_copy_string ( tmp - > chan - > language , chan - > language , sizeof ( tmp - > chan - > language ) ) ;
ast_copy_string ( tmp - > chan - > accountcode , chan - > accountcode , sizeof ( tmp - > chan - > accountcode ) ) ;
2004-07-22 03:51:54 +00:00
tmp - > chan - > cdrflags = chan - > cdrflags ;
2004-05-04 19:11:25 +00:00
if ( ast_strlen_zero ( tmp - > chan - > musicclass ) )
2005-07-07 23:32:37 +00:00
ast_copy_string ( tmp - > chan - > musicclass , chan - > musicclass , sizeof ( tmp - > chan - > musicclass ) ) ;
2004-10-31 23:34:22 +00:00
if ( chan - > cid . cid_rdnis )
tmp - > chan - > cid . cid_rdnis = strdup ( chan - > cid . cid_rdnis ) ;
2003-10-01 15:59:26 +00:00
/* Pass callingpres setting */
2004-10-02 00:58:31 +00:00
tmp - > chan - > cid . cid_pres = chan - > cid . cid_pres ;
2004-10-02 01:05:11 +00:00
/* Pass type of number */
tmp - > chan - > cid . cid_ton = chan - > cid . cid_ton ;
/* Pass type of tns */
tmp - > chan - > cid . cid_tns = chan - > cid . cid_tns ;
2001-12-20 15:21:47 +00:00
/* Presense of ADSI CPE on outgoing channel follows ours */
tmp - > chan - > adsicpe = chan - > adsicpe ;
2005-04-01 17:00:50 +00:00
/* Pass the transfer capability */
tmp - > chan - > transfercapability = chan - > transfercapability ;
2004-11-07 21:49:43 +00:00
/* If we have an outbound group, set this peer channel to it */
if ( outbound_group )
ast_app_group_set_channel ( tmp - > chan , outbound_group ) ;
1999-12-04 21:35:07 +00:00
/* Place the call, but don't wait on the answer */
1999-12-18 07:01:48 +00:00
res = ast_call ( tmp - > chan , numsubst , 0 ) ;
2003-08-14 20:48:44 +00:00
/* Save the info in cdr's that we called them */
if ( chan - > cdr )
ast_cdr_setdestchan ( chan - > cdr , tmp - > chan - > name ) ;
2004-06-20 06:24:25 +00:00
/* check the results of ast_call */
1999-12-04 21:35:07 +00:00
if ( res ) {
/* Again, keep going even if there's an error */
if ( option_debug )
ast_log ( LOG_DEBUG , " ast call on peer returned %d \n " , res ) ;
else if ( option_verbose > 2 )
1999-12-18 07:01:48 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " Couldn't call %s \n " , numsubst ) ;
1999-12-04 21:35:07 +00:00
ast_hangup ( tmp - > chan ) ;
2004-10-26 22:25:43 +00:00
tmp - > chan = NULL ;
2004-11-01 14:48:07 +00:00
cur = rest ;
1999-12-04 21:35:07 +00:00
continue ;
2005-01-16 07:58:51 +00:00
} else {
2005-02-07 15:19:34 +00:00
senddialevent ( chan , tmp - > chan ) ;
1999-12-04 21:35:07 +00:00
if ( option_verbose > 2 )
1999-12-18 07:01:48 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " Called %s \n " , numsubst ) ;
2005-11-03 21:40:36 +00:00
if ( ! ast_test_flag ( peerflags , OPT_ORIGINAL_CLID ) )
2005-02-02 20:35:25 +00:00
ast_set_callerid ( tmp - > chan , ast_strlen_zero ( chan - > macroexten ) ? chan - > exten : chan - > macroexten , get_cid_name ( cidname , sizeof ( cidname ) , chan ) , NULL ) ;
2005-01-16 07:58:51 +00:00
}
1999-12-04 21:35:07 +00:00
/* Put them in the list of outgoing thingies... We're ready now.
XXX If we ' re forcibly removed , these outgoing calls won ' t get
hung up XXX */
2005-01-05 23:05:49 +00:00
ast_set_flag ( tmp , DIAL_STILLGOING ) ;
1999-12-04 21:35:07 +00:00
tmp - > next = outgoing ;
outgoing = tmp ;
2002-09-02 15:20:28 +00:00
/* If this line is up, don't try anybody else */
if ( outgoing - > chan - > _state = = AST_STATE_UP )
break ;
2001-03-30 18:47:35 +00:00
cur = rest ;
2005-01-18 03:12:53 +00:00
} while ( cur ) ;
2001-03-30 18:47:35 +00:00
2005-11-02 21:46:52 +00:00
if ( ! ast_strlen_zero ( args . timeout ) ) {
to = atoi ( args . timeout ) ;
2004-04-02 07:47:23 +00:00
if ( to > 0 )
to * = 1000 ;
else
2005-11-02 21:46:52 +00:00
ast_log ( LOG_WARNING , " Invalid timeout specified: '%s' \n " , args . timeout ) ;
2004-04-02 07:47:23 +00:00
} else
1999-12-04 21:35:07 +00:00
to = - 1 ;
2004-06-21 18:28:35 +00:00
2004-06-22 13:53:45 +00:00
if ( outgoing ) {
2004-06-23 03:16:58 +00:00
/* Our status will at least be NOANSWER */
2005-07-07 23:32:37 +00:00
strcpy ( status , " NOANSWER " ) ;
2005-11-03 21:40:36 +00:00
if ( ast_test_flag ( outgoing , OPT_MUSICBACK ) ) {
2004-06-22 13:53:45 +00:00
moh = 1 ;
2005-11-02 21:46:52 +00:00
ast_moh_start ( chan , opt_args [ OPT_ARG_MUSICBACK ] ) ;
2005-11-03 21:40:36 +00:00
} else if ( ast_test_flag ( outgoing , OPT_RINGBACK ) ) {
2004-06-22 13:53:45 +00:00
ast_indicate ( chan , AST_CONTROL_RINGING ) ;
sentringing + + ;
}
2004-06-23 03:16:58 +00:00
} else
2005-07-07 23:32:37 +00:00
strcpy ( status , " CHANUNAVAIL " ) ;
2004-06-21 18:28:35 +00:00
2004-07-14 01:10:24 +00:00
time ( & start_time ) ;
2005-11-02 21:46:52 +00:00
peer = wait_for_answer ( chan , outgoing , & to , peerflags , & sentringing , status , sizeof ( status ) , numbusy , numnochan , numcongestion , ast_test_flag ( & opts , OPT_PRIORITY_JUMP ) , & result ) ;
2005-01-05 23:05:49 +00:00
1999-12-04 21:35:07 +00:00
if ( ! peer ) {
2005-01-18 03:12:53 +00:00
if ( result ) {
res = result ;
2005-09-07 19:13:00 +00:00
} else if ( to )
1999-12-04 21:35:07 +00:00
/* Musta gotten hung up */
res = - 1 ;
2005-01-18 03:12:53 +00:00
else
1999-12-04 21:35:07 +00:00
/* Nobody answered, next please? */
2005-09-07 19:13:00 +00:00
res = 0 ;
1999-12-04 21:35:07 +00:00
goto out ;
}
if ( peer ) {
2004-07-14 01:10:24 +00:00
time ( & answer_time ) ;
2004-06-25 03:59:07 +00:00
# ifdef OSP_SUPPORT
/* Once call is answered, ditch the OSP Handle */
2005-01-05 15:15:12 +00:00
pbx_builtin_setvar_helper ( chan , " _OSPHANDLE " , " " ) ;
2005-07-07 23:32:37 +00:00
# endif
strcpy ( status , " ANSWER " ) ;
1999-12-04 21:35:07 +00:00
/* Ah ha! Someone answered within the desired timeframe. Of course after this
we will always return with - 1 so that it is hung up properly after the
conversation . */
hanguptree ( outgoing , peer ) ;
outgoing = NULL ;
2001-12-20 15:21:47 +00:00
/* If appropriate, log that we have a destination channel */
if ( chan - > cdr )
ast_cdr_setdestchan ( chan - > cdr , peer - > name ) ;
2003-03-12 06:00:18 +00:00
if ( peer - > name )
pbx_builtin_setvar_helper ( chan , " DIALEDPEERNAME " , peer - > name ) ;
2005-01-27 16:33:12 +00:00
number = pbx_builtin_getvar_helper ( peer , " DIALEDPEERNUMBER " ) ;
if ( ! number )
number = numsubst ;
pbx_builtin_setvar_helper ( chan , " DIALEDPEERNUMBER " , number ) ;
2005-11-02 21:46:52 +00:00
if ( ! ast_strlen_zero ( args . url ) & & ast_channel_supports_html ( peer ) ) {
ast_log ( LOG_DEBUG , " app_dial: sendurl=%s. \n " , args . url ) ;
ast_channel_sendurl ( peer , args . url ) ;
2005-10-26 19:48:14 +00:00
}
2005-11-02 21:46:52 +00:00
if ( ast_test_flag ( & opts , OPT_PRIVACY ) | | ast_test_flag ( & opts , OPT_SCREENING ) ) {
2005-07-12 03:23:31 +00:00
int res2 ;
int loopcount = 0 ;
if ( privdb_val = = AST_PRIVACY_UNKNOWN ) {
/* Get the user's intro, store it in priv-callerintros/$CID,
unless it is already there - - this should be done before the
call is actually dialed */
/* all ring indications and moh for the caller has been halted as soon as the
target extension was picked up . We are going to have to kill some
time and make the caller believe the peer hasn ' t picked up yet */
2005-11-02 21:46:52 +00:00
if ( ast_test_flag ( & opts , OPT_MUSICBACK ) & & ! ast_strlen_zero ( opt_args [ OPT_ARG_MUSICBACK ] ) ) {
2005-07-12 03:23:31 +00:00
ast_indicate ( chan , - 1 ) ;
2005-11-02 21:46:52 +00:00
ast_moh_start ( chan , opt_args [ OPT_ARG_MUSICBACK ] ) ;
} else if ( ast_test_flag ( & opts , OPT_RINGBACK ) ) {
2005-07-12 03:23:31 +00:00
ast_indicate ( chan , AST_CONTROL_RINGING ) ;
sentringing + + ;
}
/* Start autoservice on the other chan ?? */
res2 = ast_autoservice_start ( chan ) ;
/* Now Stream the File */
if ( ! res2 ) {
do {
if ( ! res2 )
res2 = ast_play_and_wait ( peer , " priv-callpending " ) ;
2005-11-02 21:46:52 +00:00
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! */
2005-07-12 03:23:31 +00:00
res2 = 0 ;
/* priv-callpending script:
" I have a caller waiting, who introduces themselves as: "
*/
if ( ! res2 )
res2 = ast_play_and_wait ( peer , privintro ) ;
2005-11-02 21:46:52 +00:00
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! */
2005-07-12 03:23:31 +00:00
res2 = 0 ;
/* now get input from the called party, as to their choice */
if ( ! res2 ) {
2005-11-02 21:46:52 +00:00
if ( ast_test_flag ( & opts , OPT_PRIVACY ) )
2005-07-12 03:23:31 +00:00
res2 = ast_play_and_wait ( peer , " priv-callee-options " ) ;
2005-11-02 21:46:52 +00:00
if ( ast_test_flag ( & opts , OPT_SCREENING ) )
2005-07-12 03:23:31 +00:00
res2 = ast_play_and_wait ( peer , " screen-callee-options " ) ;
}
/* priv-callee-options script:
" Dial 1 if you wish this caller to reach you directly in the future,
and immediately connect to their incoming call
Dial 2 if you wish to send this caller to voicemail now and
forevermore .
Dial 3 to send this callerr to the torture menus , now and forevermore .
Dial 4 to send this caller to a simple " go away " menu , now and forevermore .
Dial 5 to allow this caller to come straight thru to you in the future ,
but right now , just this once , send them to voicemail . "
*/
/* screen-callee-options script:
" Dial 1 if you wish to immediately connect to the incoming call
Dial 2 if you wish to send this caller to voicemail .
Dial 3 to send this callerr to the torture menus .
Dial 4 to send this caller to a simple " go away " menu .
*/
2005-11-02 21:46:52 +00:00
if ( ! res2 | | res2 < ' 1 ' | | ( ast_test_flag ( & opts , OPT_PRIVACY ) & & res2 > ' 5 ' ) | | ( ast_test_flag ( & opts , OPT_SCREENING ) & & res2 > ' 4 ' ) ) {
2005-07-12 03:23:31 +00:00
/* invalid option */
res2 = ast_play_and_wait ( peer , " vm-sorry " ) ;
}
loopcount + + ; /* give the callee a couple chances to make a choice */
2005-11-02 21:46:52 +00:00
} while ( ( ! res2 | | res2 < ' 1 ' | | ( ast_test_flag ( & opts , OPT_PRIVACY ) & & res2 > ' 5 ' ) | | ( ast_test_flag ( & opts , OPT_SCREENING ) & & res2 > ' 4 ' ) ) & & loopcount < 2 ) ;
2005-07-12 03:23:31 +00:00
}
switch ( res2 ) {
case ' 1 ' :
2005-11-02 21:46:52 +00:00
if ( ast_test_flag ( & opts , OPT_PRIVACY ) ) {
2005-07-12 03:23:31 +00:00
if ( option_verbose > 2 )
2005-11-02 21:46:52 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " --Set privacy database entry %s/%s to ALLOW \n " ,
opt_args [ OPT_ARG_PRIVACY ] , privcid ) ;
ast_privacy_set ( opt_args [ OPT_ARG_PRIVACY ] , privcid , AST_PRIVACY_ALLOW ) ;
2005-07-12 03:23:31 +00:00
}
break ;
case ' 2 ' :
2005-11-02 21:46:52 +00:00
if ( ast_test_flag ( & opts , OPT_PRIVACY ) ) {
2005-07-12 03:23:31 +00:00
if ( option_verbose > 2 )
2005-11-02 21:46:52 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " --Set privacy database entry %s/%s to DENY \n " ,
opt_args [ OPT_ARG_PRIVACY ] , privcid ) ;
ast_privacy_set ( opt_args [ OPT_ARG_PRIVACY ] , privcid , AST_PRIVACY_DENY ) ;
2005-07-12 03:23:31 +00:00
}
2005-11-02 21:46:52 +00:00
if ( ast_test_flag ( & opts , OPT_MUSICBACK ) ) {
2005-07-12 03:23:31 +00:00
ast_moh_stop ( chan ) ;
2005-11-02 21:46:52 +00:00
} else if ( ast_test_flag ( & opts , OPT_RINGBACK ) ) {
2005-07-12 03:23:31 +00:00
ast_indicate ( chan , - 1 ) ;
sentringing = 0 ;
}
res2 = ast_autoservice_stop ( chan ) ;
ast_hangup ( peer ) ; /* hang up on the callee -- he didn't want to talk anyway! */
res = 0 ;
goto out ;
case ' 3 ' :
2005-11-02 21:46:52 +00:00
if ( ast_test_flag ( & opts , OPT_PRIVACY ) ) {
2005-07-12 03:23:31 +00:00
if ( option_verbose > 2 )
2005-11-02 21:46:52 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " --Set privacy database entry %s/%s to TORTURE \n " ,
opt_args [ OPT_ARG_PRIVACY ] , privcid ) ;
ast_privacy_set ( opt_args [ OPT_ARG_PRIVACY ] , privcid , AST_PRIVACY_TORTURE ) ;
2005-07-12 03:23:31 +00:00
}
ast_copy_string ( status , " TORTURE " , sizeof ( status ) ) ;
res = 0 ;
2005-11-02 21:46:52 +00:00
if ( ast_test_flag ( & opts , OPT_MUSICBACK ) ) {
2005-07-12 03:23:31 +00:00
ast_moh_stop ( chan ) ;
2005-11-02 21:46:52 +00:00
} else if ( ast_test_flag ( & opts , OPT_RINGBACK ) ) {
2005-07-12 03:23:31 +00:00
ast_indicate ( chan , - 1 ) ;
sentringing = 0 ;
}
res2 = ast_autoservice_stop ( chan ) ;
ast_hangup ( peer ) ; /* hang up on the caller -- he didn't want to talk anyway! */
goto out ; /* Is this right? */
case ' 4 ' :
2005-11-02 21:46:52 +00:00
if ( ast_test_flag ( & opts , OPT_PRIVACY ) ) {
2005-07-12 03:23:31 +00:00
if ( option_verbose > 2 )
2005-11-02 21:46:52 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " --Set privacy database entry %s/%s to KILL \n " ,
opt_args [ OPT_ARG_PRIVACY ] , privcid ) ;
ast_privacy_set ( opt_args [ OPT_ARG_PRIVACY ] , privcid , AST_PRIVACY_KILL ) ;
2005-07-12 03:23:31 +00:00
}
ast_copy_string ( status , " DONTCALL " , sizeof ( status ) ) ;
res = 0 ;
2005-11-02 21:46:52 +00:00
if ( ast_test_flag ( & opts , OPT_MUSICBACK ) ) {
2005-07-12 03:23:31 +00:00
ast_moh_stop ( chan ) ;
2005-11-02 21:46:52 +00:00
} else if ( ast_test_flag ( & opts , OPT_RINGBACK ) ) {
2005-07-12 03:23:31 +00:00
ast_indicate ( chan , - 1 ) ;
sentringing = 0 ;
}
res2 = ast_autoservice_stop ( chan ) ;
ast_hangup ( peer ) ; /* hang up on the caller -- he didn't want to talk anyway! */
goto out ; /* Is this right? */
case ' 5 ' :
2005-11-02 21:46:52 +00:00
if ( ast_test_flag ( & opts , OPT_PRIVACY ) ) {
2005-07-12 03:23:31 +00:00
if ( option_verbose > 2 )
2005-11-02 21:46:52 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " --Set privacy database entry %s/%s to ALLOW \n " ,
opt_args [ OPT_ARG_PRIVACY ] , privcid ) ;
ast_privacy_set ( opt_args [ OPT_ARG_PRIVACY ] , privcid , AST_PRIVACY_ALLOW ) ;
if ( ast_test_flag ( & opts , OPT_MUSICBACK ) ) {
2005-07-12 03:23:31 +00:00
ast_moh_stop ( chan ) ;
2005-11-02 21:46:52 +00:00
} else if ( ast_test_flag ( & opts , OPT_RINGBACK ) ) {
2005-07-12 03:23:31 +00:00
ast_indicate ( chan , - 1 ) ;
sentringing = 0 ;
}
res2 = ast_autoservice_stop ( chan ) ;
ast_hangup ( peer ) ; /* hang up on the caller -- he didn't want to talk anyway! */
res = 0 ;
goto out ;
} /* if not privacy, then 5 is the same as "default" case */
default :
/* well, if the user messes up, ... he had his chance... What Is The Best Thing To Do? */
/* well, there seems basically two choices. Just patch the caller thru immediately,
or , . . . put ' em thru to voicemail . */
/* since the callee may have hung up, let's do the voicemail thing, no database decision */
if ( option_verbose > 2 )
ast_log ( LOG_NOTICE , " privacy: no valid response from the callee. Sending the caller to voicemail, the callee isn't responding \n " ) ;
2005-11-02 21:46:52 +00:00
if ( ast_test_flag ( & opts , OPT_MUSICBACK ) ) {
2005-07-12 03:23:31 +00:00
ast_moh_stop ( chan ) ;
2005-11-02 21:46:52 +00:00
} else if ( ast_test_flag ( & opts , OPT_RINGBACK ) ) {
2005-07-12 03:23:31 +00:00
ast_indicate ( chan , - 1 ) ;
sentringing = 0 ;
}
res2 = ast_autoservice_stop ( chan ) ;
ast_hangup ( peer ) ; /* hang up on the callee -- he didn't want to talk anyway! */
res = 0 ;
goto out ;
}
2005-11-02 21:46:52 +00:00
if ( ast_test_flag ( & opts , OPT_MUSICBACK ) ) {
2005-07-12 03:23:31 +00:00
ast_moh_stop ( chan ) ;
2005-11-02 21:46:52 +00:00
} else if ( ast_test_flag ( & opts , OPT_RINGBACK ) ) {
2005-07-12 03:23:31 +00:00
ast_indicate ( chan , - 1 ) ;
sentringing = 0 ;
}
res2 = ast_autoservice_stop ( chan ) ;
/* if the intro is NOCALLERID, then there's no reason to leave it on disk, it'll
just clog things up , and it ' s not useful information , not being tied to a CID */
2005-11-02 21:46:52 +00:00
if ( strncmp ( privcid , " NOCALLERID " , 10 ) = = 0 | | ast_test_flag ( & opts , OPT_SCREEN_NOINTRO ) ) {
2005-07-12 03:23:31 +00:00
ast_filedelete ( privintro , NULL ) ;
if ( ast_fileexists ( privintro , NULL , NULL ) > 0 )
ast_log ( LOG_NOTICE , " privacy: ast_filedelete didn't do its job on %s \n " , privintro ) ;
else if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Successfully deleted %s intro file \n " , privintro ) ;
}
}
}
2005-11-02 21:46:52 +00:00
if ( ast_test_flag ( & opts , OPT_ANNOUNCE ) & & ! ast_strlen_zero ( opt_args [ OPT_ARG_ANNOUNCE ] ) ) {
2004-12-19 21:13:41 +00:00
/* Start autoservice on the other chan */
2004-05-07 20:39:14 +00:00
res = ast_autoservice_start ( chan ) ;
2004-12-19 21:13:41 +00:00
/* Now Stream the File */
2004-05-07 20:39:14 +00:00
if ( ! res )
2005-11-02 21:46:52 +00:00
res = ast_streamfile ( peer , opt_args [ OPT_ARG_ANNOUNCE ] , peer - > language ) ;
2004-05-20 00:29:09 +00:00
if ( ! res ) {
digit = ast_waitstream ( peer , AST_DIGIT_ANY ) ;
}
2004-12-19 21:13:41 +00:00
/* Ok, done. stop autoservice */
2004-05-07 20:39:14 +00:00
res = ast_autoservice_stop ( chan ) ;
2004-05-20 00:29:09 +00:00
if ( digit > 0 & & ! res )
res = ast_senddigit ( chan , digit ) ;
else
res = digit ;
2004-05-07 21:14:55 +00:00
} else
res = 0 ;
2005-03-17 22:39:04 +00:00
2005-11-02 21:46:52 +00:00
if ( chan & & peer & & ast_test_flag ( & opts , OPT_GOTO ) & & ! ast_strlen_zero ( opt_args [ OPT_ARG_GOTO ] ) ) {
char * ch ;
for ( ch = opt_args [ OPT_ARG_GOTO ] ; * ch ; ch + + ) {
if ( * ch = = ' ^ ' )
* ch = ' | ' ;
2005-03-17 22:39:04 +00:00
}
2005-11-02 21:46:52 +00:00
ast_parseable_goto ( chan , opt_args [ OPT_ARG_GOTO ] ) ;
ast_parseable_goto ( peer , opt_args [ OPT_ARG_GOTO ] ) ;
2005-03-17 22:39:04 +00:00
peer - > priority + + ;
ast_pbx_start ( peer ) ;
hanguptree ( outgoing , NULL ) ;
LOCAL_USER_REMOVE ( u ) ;
return 0 ;
}
2003-07-02 14:06:12 +00:00
2005-11-02 21:46:52 +00:00
if ( ast_test_flag ( & opts , OPT_CALLEE_MACRO ) & & ! ast_strlen_zero ( opt_args [ OPT_ARG_CALLEE_MACRO ] ) ) {
char * ch ;
2004-09-10 02:31:30 +00:00
res = ast_autoservice_start ( chan ) ;
if ( res ) {
ast_log ( LOG_ERROR , " Unable to start autoservice on calling channel \n " ) ;
res = - 1 ;
}
app = pbx_findapp ( " Macro " ) ;
if ( app & & ! res ) {
2005-11-02 21:46:52 +00:00
for ( ch = opt_args [ OPT_ARG_CALLEE_MACRO ] ; * ch ; ch + + ) {
if ( * ch = = ' ^ ' )
* ch = ' | ' ;
}
res = pbx_exec ( peer , app , opt_args [ OPT_ARG_CALLEE_MACRO ] , 1 ) ;
2004-09-10 02:31:30 +00:00
ast_log ( LOG_DEBUG , " Macro exited with status %d \n " , res ) ;
res = 0 ;
} else {
ast_log ( LOG_ERROR , " Could not find application Macro \n " ) ;
res = - 1 ;
}
if ( ast_autoservice_stop ( chan ) < 0 ) {
ast_log ( LOG_ERROR , " Could not stop autoservice on calling channel \n " ) ;
res = - 1 ;
}
2004-11-22 22:11:10 +00:00
if ( ! res ) {
if ( ( macro_result = pbx_builtin_getvar_helper ( peer , " MACRO_RESULT " ) ) ) {
if ( ! strcasecmp ( macro_result , " BUSY " ) ) {
2005-07-07 23:32:37 +00:00
ast_copy_string ( status , macro_result , sizeof ( status ) ) ;
2005-11-06 05:00:42 +00:00
if ( option_priority_jumping | | ast_test_flag ( & opts , OPT_PRIORITY_JUMP ) ) {
if ( ! ast_goto_if_exists ( chan , NULL , NULL , chan - > priority + 101 ) ) {
ast_set_flag ( peerflags , OPT_GO_ON ) ;
}
} else
2005-11-03 21:40:36 +00:00
ast_set_flag ( peerflags , OPT_GO_ON ) ;
2004-11-22 22:11:10 +00:00
res = - 1 ;
}
else if ( ! strcasecmp ( macro_result , " CONGESTION " ) | | ! strcasecmp ( macro_result , " CHANUNAVAIL " ) ) {
2005-07-07 23:32:37 +00:00
ast_copy_string ( status , macro_result , sizeof ( status ) ) ;
2005-11-03 21:40:36 +00:00
ast_set_flag ( peerflags , OPT_GO_ON ) ;
2004-11-22 22:11:10 +00:00
res = - 1 ;
}
else if ( ! strcasecmp ( macro_result , " CONTINUE " ) ) {
/* hangup peer and keep chan alive assuming the macro has changed
the context / exten / priority or perhaps
the next priority in the current exten is desired .
*/
2005-11-03 21:40:36 +00:00
ast_set_flag ( peerflags , OPT_GO_ON ) ;
2004-11-22 22:11:10 +00:00
res = - 1 ;
} else if ( ! strcasecmp ( macro_result , " ABORT " ) ) {
/* Hangup both ends unless the caller has the g flag */
res = - 1 ;
2005-01-18 03:12:53 +00:00
} else if ( ! strncasecmp ( macro_result , " GOTO: " , 5 ) & & ( macro_transfer_dest = ast_strdupa ( macro_result + 5 ) ) ) {
2004-11-22 22:11:10 +00:00
res = - 1 ;
/* perform a transfer to a new extension */
2005-01-18 03:12:53 +00:00
if ( strchr ( macro_transfer_dest , ' ^ ' ) ) { /* context^exten^priority*/
2004-11-22 22:11:10 +00:00
/* no brainer mode... substitute ^ with | and feed it to builtin goto */
2005-01-18 03:12:53 +00:00
for ( res = 0 ; res < strlen ( macro_transfer_dest ) ; res + + )
if ( macro_transfer_dest [ res ] = = ' ^ ' )
2004-11-22 22:11:10 +00:00
macro_transfer_dest [ res ] = ' | ' ;
2005-01-18 03:12:53 +00:00
if ( ! ast_parseable_goto ( chan , macro_transfer_dest ) )
2005-11-03 21:40:36 +00:00
ast_set_flag ( peerflags , OPT_GO_ON ) ;
2005-01-05 23:05:49 +00:00
2004-11-22 22:11:10 +00:00
}
}
}
}
2004-09-10 02:31:30 +00:00
}
2004-05-07 21:14:55 +00:00
if ( ! res ) {
if ( calldurationlimit > 0 ) {
2005-11-02 21:46:52 +00:00
time_t now ;
2004-05-07 21:14:55 +00:00
time ( & now ) ;
chan - > whentohangup = now + calldurationlimit ;
}
2005-10-26 19:48:14 +00:00
if ( ! ast_strlen_zero ( dtmfcalled ) ) {
2005-04-11 02:46:25 +00:00
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Sending DTMF '%s' to the called party. \n " , dtmfcalled ) ;
res = ast_dtmf_stream ( peer , chan , dtmfcalled , 250 ) ;
}
2005-10-26 19:48:14 +00:00
if ( ! ast_strlen_zero ( dtmfcalling ) ) {
2005-04-11 02:46:25 +00:00
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Sending DTMF '%s' to the calling party. \n " , dtmfcalling ) ;
res = ast_dtmf_stream ( chan , peer , dtmfcalling , 250 ) ;
}
2004-05-07 20:39:14 +00:00
}
2004-05-07 21:14:55 +00:00
if ( ! res ) {
2005-11-02 21:46:52 +00:00
char toast [ 80 ] ;
2004-05-07 21:14:55 +00:00
memset ( & config , 0 , sizeof ( struct ast_bridge_config ) ) ;
2005-01-04 04:01:40 +00:00
if ( play_to_caller )
2005-01-10 14:46:59 +00:00
ast_set_flag ( & ( config . features_caller ) , AST_FEATURE_PLAY_WARNING ) ;
2005-01-04 04:01:40 +00:00
if ( play_to_callee )
2005-01-10 14:46:59 +00:00
ast_set_flag ( & ( config . features_callee ) , AST_FEATURE_PLAY_WARNING ) ;
2005-11-03 21:40:36 +00:00
if ( ast_test_flag ( peerflags , OPT_CALLEE_TRANSFER ) )
2005-01-10 14:46:59 +00:00
ast_set_flag ( & ( config . features_callee ) , AST_FEATURE_REDIRECT ) ;
2005-11-03 21:40:36 +00:00
if ( ast_test_flag ( peerflags , OPT_CALLER_TRANSFER ) )
2005-01-10 14:46:59 +00:00
ast_set_flag ( & ( config . features_caller ) , AST_FEATURE_REDIRECT ) ;
2005-11-03 21:40:36 +00:00
if ( ast_test_flag ( peerflags , OPT_CALLEE_HANGUP ) )
2005-01-10 14:46:59 +00:00
ast_set_flag ( & ( config . features_callee ) , AST_FEATURE_DISCONNECT ) ;
2005-11-03 21:40:36 +00:00
if ( ast_test_flag ( peerflags , OPT_CALLER_HANGUP ) )
2005-01-10 14:46:59 +00:00
ast_set_flag ( & ( config . features_caller ) , AST_FEATURE_DISCONNECT ) ;
2005-11-03 21:40:36 +00:00
if ( ast_test_flag ( peerflags , OPT_CALLEE_MONITOR ) )
2005-01-10 14:46:59 +00:00
ast_set_flag ( & ( config . features_callee ) , AST_FEATURE_AUTOMON ) ;
2005-11-03 21:40:36 +00:00
if ( ast_test_flag ( peerflags , OPT_CALLER_MONITOR ) )
2005-01-10 14:46:59 +00:00
ast_set_flag ( & ( config . features_caller ) , AST_FEATURE_AUTOMON ) ;
2005-01-18 03:12:53 +00:00
2004-05-07 21:14:55 +00:00
config . timelimit = timelimit ;
config . play_warning = play_warning ;
config . warning_freq = warning_freq ;
config . warning_sound = warning_sound ;
config . end_sound = end_sound ;
config . start_sound = start_sound ;
2004-06-21 18:28:35 +00:00
if ( moh ) {
moh = 0 ;
ast_moh_stop ( chan ) ;
} else if ( sentringing ) {
sentringing = 0 ;
ast_indicate ( chan , - 1 ) ;
}
2004-07-07 16:02:13 +00:00
/* Be sure no generators are left on it */
ast_deactivate_generator ( chan ) ;
/* Make sure channels are compatible */
res = ast_channel_make_compatible ( chan , peer ) ;
if ( res < 0 ) {
ast_log ( LOG_WARNING , " Had to drop call because I couldn't make %s compatible with %s \n " , chan - > name , peer - > name ) ;
ast_hangup ( peer ) ;
2005-10-19 18:19:02 +00:00
LOCAL_USER_REMOVE ( u ) ;
2004-07-07 16:02:13 +00:00
return - 1 ;
}
2004-05-07 21:14:55 +00:00
res = ast_bridge_call ( chan , peer , & config ) ;
2004-07-14 01:10:24 +00:00
time ( & end_time ) ;
snprintf ( toast , sizeof ( toast ) , " %ld " , ( long ) ( end_time - start_time ) ) ;
pbx_builtin_setvar_helper ( chan , " DIALEDTIME " , toast ) ;
snprintf ( toast , sizeof ( toast ) , " %ld " , ( long ) ( end_time - answer_time ) ) ;
pbx_builtin_setvar_helper ( chan , " ANSWEREDTIME " , toast ) ;
2004-05-07 21:14:55 +00:00
} else
res = - 1 ;
2004-05-07 20:39:14 +00:00
2004-05-22 23:17:33 +00:00
if ( res ! = AST_PBX_NO_HANGUP_PEER ) {
if ( ! chan - > _softhangup )
chan - > hangupcause = peer - > hangupcause ;
2004-05-07 21:14:55 +00:00
ast_hangup ( peer ) ;
2004-05-22 23:17:33 +00:00
}
1999-12-04 21:35:07 +00:00
}
out :
2004-06-21 18:28:35 +00:00
if ( moh ) {
moh = 0 ;
ast_moh_stop ( chan ) ;
} else if ( sentringing ) {
sentringing = 0 ;
ast_indicate ( chan , - 1 ) ;
}
1999-12-04 21:35:07 +00:00
hanguptree ( outgoing , NULL ) ;
2004-06-23 03:16:58 +00:00
pbx_builtin_setvar_helper ( chan , " DIALSTATUS " , status ) ;
2004-07-20 22:24:15 +00:00
ast_log ( LOG_DEBUG , " Exiting with DIALSTATUS=%s. \n " , status ) ;
2004-06-23 03:16:58 +00:00
2005-11-03 21:40:36 +00:00
if ( ( ast_test_flag ( peerflags , OPT_GO_ON ) ) & & ( ! chan - > _softhangup ) & & ( res ! = AST_PBX_KEEPALIVE ) )
2005-10-19 18:19:02 +00:00
res = 0 ;
LOCAL_USER_REMOVE ( u ) ;
1999-12-04 21:35:07 +00:00
return res ;
}
2005-01-18 03:12:53 +00:00
static int dial_exec ( struct ast_channel * chan , void * data )
{
struct ast_flags peerflags ;
memset ( & peerflags , 0 , sizeof ( peerflags ) ) ;
return dial_exec_full ( chan , data , & peerflags ) ;
}
static int retrydial_exec ( struct ast_channel * chan , void * data )
{
char * announce = NULL , * context = NULL , * dialdata = NULL ;
int sleep = 0 , loops = 0 , res = 0 ;
2005-10-19 18:19:02 +00:00
struct localuser * u ;
2005-01-18 03:12:53 +00:00
struct ast_flags peerflags ;
2005-10-26 19:48:14 +00:00
if ( ast_strlen_zero ( data ) ) {
2005-10-19 18:19:02 +00:00
ast_log ( LOG_WARNING , " RetryDial requires an argument! \n " ) ;
return - 1 ;
}
2005-01-18 03:12:53 +00:00
LOCAL_USER_ADD ( u ) ;
2005-10-19 18:19:02 +00:00
announce = ast_strdupa ( data ) ;
if ( ! announce ) {
2005-01-18 03:12:53 +00:00
ast_log ( LOG_ERROR , " Out of memory! \n " ) ;
LOCAL_USER_REMOVE ( u ) ;
return - 1 ;
}
2005-10-19 18:19:02 +00:00
memset ( & peerflags , 0 , sizeof ( peerflags ) ) ;
2005-01-18 03:12:53 +00:00
if ( ( dialdata = strchr ( announce , ' | ' ) ) ) {
* dialdata = ' \0 ' ;
dialdata + + ;
if ( ( sleep = atoi ( dialdata ) ) ) {
sleep * = 1000 ;
} else {
2005-02-09 22:59:46 +00:00
ast_log ( LOG_ERROR , " %s requires the numerical argument <sleep> \n " , rapp ) ;
2005-01-18 03:12:53 +00:00
LOCAL_USER_REMOVE ( u ) ;
return - 1 ;
}
if ( ( dialdata = strchr ( dialdata , ' | ' ) ) ) {
* dialdata = ' \0 ' ;
dialdata + + ;
if ( ! ( loops = atoi ( dialdata ) ) ) {
2005-02-09 22:59:46 +00:00
ast_log ( LOG_ERROR , " %s requires the numerical argument <loops> \n " , rapp ) ;
2005-01-18 03:12:53 +00:00
LOCAL_USER_REMOVE ( u ) ;
return - 1 ;
}
}
}
if ( ( dialdata = strchr ( dialdata , ' | ' ) ) ) {
* dialdata = ' \0 ' ;
dialdata + + ;
} else {
2005-02-09 22:59:46 +00:00
ast_log ( LOG_ERROR , " %s requires more arguments \n " , rapp ) ;
2005-01-18 03:12:53 +00:00
LOCAL_USER_REMOVE ( u ) ;
return - 1 ;
}
if ( sleep < 1000 )
sleep = 10000 ;
if ( ! loops )
loops = - 1 ;
context = pbx_builtin_getvar_helper ( chan , " EXITCONTEXT " ) ;
while ( loops ) {
chan - > data = " Retrying " ;
if ( ast_test_flag ( chan , AST_FLAG_MOH ) )
ast_moh_stop ( chan ) ;
2005-01-20 22:59:50 +00:00
if ( ( res = dial_exec_full ( chan , dialdata , & peerflags ) ) = = 0 ) {
2005-11-03 21:40:36 +00:00
if ( ast_test_flag ( & peerflags , OPT_DTMF_EXIT ) ) {
2005-01-18 03:12:53 +00:00
if ( ! ( res = ast_streamfile ( chan , announce , chan - > language ) ) )
res = ast_waitstream ( chan , AST_DIGIT_ANY ) ;
2005-01-20 22:59:50 +00:00
if ( ! res & & sleep ) {
2005-01-18 03:12:53 +00:00
if ( ! ast_test_flag ( chan , AST_FLAG_MOH ) )
ast_moh_start ( chan , NULL ) ;
res = ast_waitfordigit ( chan , sleep ) ;
}
} else {
if ( ! ( res = ast_streamfile ( chan , announce , chan - > language ) ) )
res = ast_waitstream ( chan , " " ) ;
2005-01-20 22:59:50 +00:00
if ( sleep ) {
if ( ! ast_test_flag ( chan , AST_FLAG_MOH ) )
ast_moh_start ( chan , NULL ) ;
if ( ! res )
2005-06-01 18:02:46 +00:00
res = ast_waitfordigit ( chan , sleep ) ;
2005-01-20 22:59:50 +00:00
}
2005-01-18 03:12:53 +00:00
}
}
if ( res < 0 )
break ;
else if ( res > 0 ) { /* Trying to send the call elsewhere (1 digit ext) */
2005-04-29 15:04:26 +00:00
if ( onedigit_goto ( chan , context , ( char ) res , 1 ) ) {
2005-01-18 03:12:53 +00:00
res = 0 ;
break ;
}
}
loops - - ;
}
if ( ast_test_flag ( chan , AST_FLAG_MOH ) )
ast_moh_stop ( chan ) ;
LOCAL_USER_REMOVE ( u ) ;
return loops ? res : 0 ;
}
1999-12-04 21:35:07 +00:00
int unload_module ( void )
{
2005-10-18 22:52:21 +00:00
int res ;
res = ast_unregister_application ( app ) ;
res | = ast_unregister_application ( rapp ) ;
1999-12-04 21:35:07 +00:00
STANDARD_HANGUP_LOCALUSERS ;
2005-10-18 22:52:21 +00:00
return res ;
1999-12-04 21:35:07 +00:00
}
int load_module ( void )
{
2000-03-26 01:59:06 +00:00
int res ;
2005-10-18 22:52:21 +00:00
res = ast_register_application ( app , dial_exec , synopsis , descrip ) ;
res | = ast_register_application ( rapp , retrydial_exec , rsynopsis , rdescrip ) ;
2000-03-26 01:59:06 +00:00
return res ;
1999-12-04 21:35:07 +00:00
}
char * description ( void )
{
return tdesc ;
}
int usecount ( void )
{
int res ;
STANDARD_USECOUNT ( res ) ;
return res ;
}
2001-03-30 18:47:35 +00:00
char * key ( )
{
return ASTERISK_GPL_KEY ;
}