2007-01-24 18:23:07 +00:00
/*
* Asterisk - - An open source telephony toolkit .
*
* Copyright ( C ) 1999 - 2007 , Digium , Inc .
*
* Joshua Colp < jcolp @ digium . com >
*
* 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 .
*
* This program is free software , distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree .
*/
/*! \file
*
* \ brief Dialing API
*
2008-01-24 03:25:52 +00:00
* \ author Joshua Colp < jcolp @ digium . com >
2007-01-24 18:23:07 +00:00
*/
# include "asterisk.h"
ASTERISK_FILE_VERSION ( __FILE__ , " $Revision$ " )
# include <sys/time.h>
# include <signal.h>
# include "asterisk/channel.h"
# include "asterisk/utils.h"
# include "asterisk/lock.h"
# include "asterisk/linkedlists.h"
# include "asterisk/dial.h"
# include "asterisk/pbx.h"
2007-04-10 19:16:24 +00:00
# include "asterisk/musiconhold.h"
2007-01-24 18:23:07 +00:00
/*! \brief Main dialing structure. Contains global options, channels being dialed, and more! */
struct ast_dial {
2007-04-28 21:01:44 +00:00
int num ; /*!< Current number to give to next dialed channel */
2007-07-30 20:42:28 +00:00
int timeout ; /*!< Maximum time allowed for dial attempts */
int actual_timeout ; /*!< Actual timeout based on all factors (ie: channels) */
2007-04-28 21:01:44 +00:00
enum ast_dial_result state ; /*!< Status of dial */
void * options [ AST_DIAL_OPTION_MAX ] ; /*!< Global options */
ast_dial_state_callback state_callback ; /*!< Status callback */
2008-02-28 20:14:04 +00:00
AST_LIST_HEAD ( , ast_dial_channel ) channels ; /*!< Channels being dialed */
2007-04-28 21:01:44 +00:00
pthread_t thread ; /*!< Thread (if running in async) */
2008-01-16 15:09:37 +00:00
ast_mutex_t lock ; /*! Lock to protect the thread information above */
2007-01-24 18:23:07 +00:00
} ;
/*! \brief Dialing channel structure. Contains per-channel dialing options, asterisk channel, and more! */
struct ast_dial_channel {
2008-10-30 16:49:02 +00:00
int num ; /*!< Unique number for dialed channel */
int timeout ; /*!< Maximum time allowed for attempt */
char * tech ; /*!< Technology being dialed */
char * device ; /*!< Device being dialed */
void * options [ AST_DIAL_OPTION_MAX ] ; /*!< Channel specific options */
int cause ; /*!< Cause code in case of failure */
unsigned int is_running_app : 1 ; /*!< Is this running an application? */
struct ast_channel * owner ; /*!< Asterisk channel */
AST_LIST_ENTRY ( ast_dial_channel ) list ; /*!< Linked list information */
2007-01-24 18:23:07 +00:00
} ;
/*! \brief Typedef for dial option enable */
typedef void * ( * ast_dial_option_cb_enable ) ( void * data ) ;
/*! \brief Typedef for dial option disable */
typedef int ( * ast_dial_option_cb_disable ) ( void * data ) ;
2007-05-16 07:08:48 +00:00
/*! \brief Structure for 'ANSWER_EXEC' option */
2007-01-24 18:23:07 +00:00
struct answer_exec_struct {
2007-05-16 07:08:48 +00:00
char app [ AST_MAX_APP ] ; /*!< Application name */
char * args ; /*!< Application arguments */
2007-01-24 18:23:07 +00:00
} ;
2007-05-16 07:08:48 +00:00
/*! \brief Enable function for 'ANSWER_EXEC' option */
2007-01-24 18:23:07 +00:00
static void * answer_exec_enable ( void * data )
{
struct answer_exec_struct * answer_exec = NULL ;
char * app = ast_strdupa ( ( char * ) data ) , * args = NULL ;
/* Not giving any data to this option is bad, mmmk? */
if ( ast_strlen_zero ( app ) )
return NULL ;
/* Create new data structure */
if ( ! ( answer_exec = ast_calloc ( 1 , sizeof ( * answer_exec ) ) ) )
return NULL ;
/* Parse out application and arguments */
2008-06-13 14:15:07 +00:00
if ( ( args = strchr ( app , ' , ' ) ) ) {
2007-01-24 18:23:07 +00:00
* args + + = ' \0 ' ;
answer_exec - > args = ast_strdup ( args ) ;
}
/* Copy application name */
ast_copy_string ( answer_exec - > app , app , sizeof ( answer_exec - > app ) ) ;
return answer_exec ;
}
2007-05-16 07:08:48 +00:00
/*! \brief Disable function for 'ANSWER_EXEC' option */
2007-01-24 18:23:07 +00:00
static int answer_exec_disable ( void * data )
{
struct answer_exec_struct * answer_exec = data ;
/* Make sure we have a value */
if ( ! answer_exec )
return - 1 ;
/* If arguments are present, free them too */
if ( answer_exec - > args )
2007-06-06 21:20:11 +00:00
ast_free ( answer_exec - > args ) ;
2007-01-24 18:23:07 +00:00
/* This is simple - just free the structure */
2007-06-06 21:20:11 +00:00
ast_free ( answer_exec ) ;
2007-01-24 18:23:07 +00:00
return 0 ;
}
2007-04-10 19:16:24 +00:00
static void * music_enable ( void * data )
{
return ast_strdup ( data ) ;
}
static int music_disable ( void * data )
{
if ( ! data )
return - 1 ;
2007-06-06 21:20:11 +00:00
ast_free ( data ) ;
2007-04-10 19:16:24 +00:00
return 0 ;
}
2007-05-16 07:08:48 +00:00
/*! \brief Application execution function for 'ANSWER_EXEC' option */
2007-11-26 21:14:07 +00:00
static void answer_exec_run ( struct ast_dial * dial , struct ast_dial_channel * dial_channel , char * app , char * args )
2007-01-24 18:23:07 +00:00
{
2007-11-26 21:14:07 +00:00
struct ast_channel * chan = dial_channel - > owner ;
2007-01-24 18:23:07 +00:00
struct ast_app * ast_app = pbx_findapp ( app ) ;
/* If the application was not found, return immediately */
if ( ! ast_app )
return ;
/* All is well... execute the application */
pbx_exec ( chan , ast_app , args ) ;
2007-11-26 21:14:07 +00:00
/* If another thread is not taking over hang up the channel */
2008-01-16 15:09:37 +00:00
ast_mutex_lock ( & dial - > lock ) ;
2007-11-26 21:14:07 +00:00
if ( dial - > thread ! = AST_PTHREADT_STOP ) {
ast_hangup ( chan ) ;
dial_channel - > owner = NULL ;
}
2008-01-16 15:09:37 +00:00
ast_mutex_unlock ( & dial - > lock ) ;
2007-11-26 21:14:07 +00:00
2007-01-24 18:23:07 +00:00
return ;
}
/*! \brief Options structure - maps options to respective handlers (enable/disable). This list MUST be perfectly kept in order, or else madness will happen. */
static const struct ast_option_types {
enum ast_dial_option option ;
ast_dial_option_cb_enable enable ;
ast_dial_option_cb_disable disable ;
} option_types [ ] = {
2007-04-10 19:16:24 +00:00
{ AST_DIAL_OPTION_RINGING , NULL , NULL } , /*!< Always indicate ringing to caller */
{ AST_DIAL_OPTION_ANSWER_EXEC , answer_exec_enable , answer_exec_disable } , /*!< Execute application upon answer in async mode */
{ AST_DIAL_OPTION_MUSIC , music_enable , music_disable } , /*!< Play music to the caller instead of ringing */
2007-07-30 20:42:28 +00:00
{ AST_DIAL_OPTION_DISABLE_CALL_FORWARDING , NULL , NULL } , /*!< Disable call forwarding on channels */
2007-04-10 19:16:24 +00:00
{ AST_DIAL_OPTION_MAX , NULL , NULL } , /*!< Terminator of list */
2007-01-24 18:23:07 +00:00
} ;
2007-05-16 07:08:48 +00:00
/*! \brief free the buffer if allocated, and set the pointer to the second arg */
2008-03-04 23:04:29 +00:00
# define S_REPLACE(s, new_val) \
do { \
if ( s ) { \
free ( s ) ; \
} \
s = ( new_val ) ; \
} while ( 0 )
2007-01-24 18:23:07 +00:00
/*! \brief Maximum number of channels we can watch at a time */
# define AST_MAX_WATCHERS 256
/*! \brief Macro for finding the option structure to use on a dialed channel */
# define FIND_RELATIVE_OPTION(dial, dial_channel, ast_dial_option) (dial_channel->options[ast_dial_option] ? dial_channel->options[ast_dial_option] : dial->options[ast_dial_option])
/*! \brief Macro that determines whether a channel is the caller or not */
# define IS_CALLER(chan, owner) (chan == owner ? 1 : 0)
/*! \brief New dialing structure
* \ note Create a dialing structure
* \ return Returns a calloc ' d ast_dial structure , NULL on failure
*/
struct ast_dial * ast_dial_create ( void )
{
struct ast_dial * dial = NULL ;
/* Allocate new memory for structure */
if ( ! ( dial = ast_calloc ( 1 , sizeof ( * dial ) ) ) )
return NULL ;
/* Initialize list of channels */
2008-02-28 20:14:04 +00:00
AST_LIST_HEAD_INIT ( & dial - > channels ) ;
2007-01-24 18:23:07 +00:00
/* Initialize thread to NULL */
dial - > thread = AST_PTHREADT_NULL ;
2007-07-30 20:42:28 +00:00
/* No timeout exists... yet */
dial - > timeout = - 1 ;
dial - > actual_timeout = - 1 ;
2008-01-16 15:09:37 +00:00
/* Can't forget about the lock */
ast_mutex_init ( & dial - > lock ) ;
2007-01-24 18:23:07 +00:00
return dial ;
}
/*! \brief Append a channel
* \ note Appends a channel to a dialing structure
* \ return Returns channel reference number on success , - 1 on failure
*/
int ast_dial_append ( struct ast_dial * dial , const char * tech , const char * device )
{
struct ast_dial_channel * channel = NULL ;
/* Make sure we have required arguments */
if ( ! dial | | ! tech | | ! device )
return - 1 ;
/* Allocate new memory for dialed channel structure */
if ( ! ( channel = ast_calloc ( 1 , sizeof ( * channel ) ) ) )
return - 1 ;
/* Record technology and device for when we actually dial */
2007-07-30 20:42:28 +00:00
channel - > tech = ast_strdup ( tech ) ;
channel - > device = ast_strdup ( device ) ;
2007-01-24 18:23:07 +00:00
/* Grab reference number from dial structure */
channel - > num = ast_atomic_fetchadd_int ( & dial - > num , + 1 ) ;
2007-07-30 20:42:28 +00:00
/* No timeout exists... yet */
channel - > timeout = - 1 ;
2007-01-24 18:23:07 +00:00
/* Insert into channels list */
AST_LIST_INSERT_TAIL ( & dial - > channels , channel , list ) ;
return channel - > num ;
}
2007-07-30 20:42:28 +00:00
/*! \brief Helper function that does the beginning dialing per-appended channel */
static int begin_dial_channel ( struct ast_dial_channel * channel , struct ast_channel * chan )
{
char numsubst [ AST_MAX_EXTENSION ] ;
int res = 1 ;
/* Copy device string over */
ast_copy_string ( numsubst , channel - > device , sizeof ( numsubst ) ) ;
/* If we fail to create our owner channel bail out */
if ( ! ( channel - > owner = ast_request ( channel - > tech , chan ? chan - > nativeformats : AST_FORMAT_AUDIO_MASK , numsubst , & channel - > cause ) ) )
return - 1 ;
channel - > owner - > appl = " AppDial2 " ;
channel - > owner - > data = " (Outgoing Line) " ;
2008-05-01 23:06:23 +00:00
memset ( & channel - > owner - > whentohangup , 0 , sizeof ( channel - > owner - > whentohangup ) ) ;
2007-07-30 20:42:28 +00:00
/* Inherit everything from he who spawned this dial */
if ( chan ) {
ast_channel_inherit_variables ( chan , channel - > owner ) ;
2008-10-03 17:35:37 +00:00
ast_channel_datastore_inherit ( chan , channel - > owner ) ;
2007-07-30 20:42:28 +00:00
/* Copy over callerid information */
S_REPLACE ( channel - > owner - > cid . cid_num , ast_strdup ( chan - > cid . cid_num ) ) ;
S_REPLACE ( channel - > owner - > cid . cid_name , ast_strdup ( chan - > cid . cid_name ) ) ;
S_REPLACE ( channel - > owner - > cid . cid_ani , ast_strdup ( chan - > cid . cid_ani ) ) ;
S_REPLACE ( channel - > owner - > cid . cid_rdnis , ast_strdup ( chan - > cid . cid_rdnis ) ) ;
ast_string_field_set ( channel - > owner , language , chan - > language ) ;
ast_string_field_set ( channel - > owner , accountcode , chan - > accountcode ) ;
channel - > owner - > cdrflags = chan - > cdrflags ;
if ( ast_strlen_zero ( channel - > owner - > musicclass ) )
ast_string_field_set ( channel - > owner , musicclass , chan - > musicclass ) ;
channel - > owner - > cid . cid_pres = chan - > cid . cid_pres ;
channel - > owner - > cid . cid_ton = chan - > cid . cid_ton ;
channel - > owner - > cid . cid_tns = chan - > cid . cid_tns ;
channel - > owner - > adsicpe = chan - > adsicpe ;
channel - > owner - > transfercapability = chan - > transfercapability ;
}
/* Attempt to actually call this device */
if ( ( res = ast_call ( channel - > owner , numsubst , 0 ) ) ) {
res = 0 ;
ast_hangup ( channel - > owner ) ;
channel - > owner = NULL ;
} else {
2007-08-10 18:37:32 +00:00
if ( chan )
ast_poll_channel_add ( chan , channel - > owner ) ;
2007-07-30 20:42:28 +00:00
res = 1 ;
ast_verb ( 3 , " Called %s \n " , numsubst ) ;
}
return res ;
}
/*! \brief Helper function that does the beginning dialing per dial structure */
2007-01-24 18:23:07 +00:00
static int begin_dial ( struct ast_dial * dial , struct ast_channel * chan )
{
struct ast_dial_channel * channel = NULL ;
2007-07-30 20:42:28 +00:00
int success = 0 ;
2007-01-24 18:23:07 +00:00
/* Iterate through channel list, requesting and calling each one */
2008-02-28 20:14:04 +00:00
AST_LIST_LOCK ( & dial - > channels ) ;
2007-01-24 18:23:07 +00:00
AST_LIST_TRAVERSE ( & dial - > channels , channel , list ) {
2007-07-30 20:42:28 +00:00
success + = begin_dial_channel ( channel , chan ) ;
}
2008-03-20 18:01:36 +00:00
AST_LIST_UNLOCK ( & dial - > channels ) ;
2007-07-30 20:42:28 +00:00
/* If number of failures matches the number of channels, then this truly failed */
return success ;
}
2007-01-24 18:23:07 +00:00
2007-07-30 20:42:28 +00:00
/*! \brief Helper function to handle channels that have been call forwarded */
static int handle_call_forward ( struct ast_dial * dial , struct ast_dial_channel * channel , struct ast_channel * chan )
{
struct ast_channel * original = channel - > owner ;
char * tmp = ast_strdupa ( channel - > owner - > call_forward ) ;
char * tech = " Local " , * device = tmp , * stuff ;
2007-01-24 18:23:07 +00:00
2007-07-30 20:42:28 +00:00
/* If call forwarding is disabled just drop the original channel and don't attempt to dial the new one */
if ( FIND_RELATIVE_OPTION ( dial , channel , AST_DIAL_OPTION_DISABLE_CALL_FORWARDING ) ) {
ast_hangup ( original ) ;
channel - > owner = NULL ;
return 0 ;
}
2007-01-24 18:23:07 +00:00
2007-07-30 20:42:28 +00:00
/* Figure out the new destination */
if ( ( stuff = strchr ( tmp , ' / ' ) ) ) {
* stuff + + = ' \0 ' ;
tech = tmp ;
device = stuff ;
}
2007-01-24 18:23:07 +00:00
2007-07-30 20:42:28 +00:00
/* Drop old destination information */
ast_free ( channel - > tech ) ;
ast_free ( channel - > device ) ;
2007-02-10 00:40:57 +00:00
2007-07-30 20:42:28 +00:00
/* Update the dial channel with the new destination information */
channel - > tech = ast_strdup ( tech ) ;
channel - > device = ast_strdup ( device ) ;
2008-02-28 20:14:04 +00:00
AST_LIST_UNLOCK ( & dial - > channels ) ;
2007-01-24 18:23:07 +00:00
2007-07-30 20:42:28 +00:00
/* Finally give it a go... send it out into the world */
begin_dial_channel ( channel , chan ) ;
2007-01-24 18:23:07 +00:00
2007-07-30 20:42:28 +00:00
/* Drop the original channel */
ast_hangup ( original ) ;
return 0 ;
2007-01-24 18:23:07 +00:00
}
/*! \brief Helper function that finds the dialed channel based on owner */
static struct ast_dial_channel * find_relative_dial_channel ( struct ast_dial * dial , struct ast_channel * owner )
{
struct ast_dial_channel * channel = NULL ;
2008-02-28 20:14:04 +00:00
AST_LIST_LOCK ( & dial - > channels ) ;
2007-01-24 18:23:07 +00:00
AST_LIST_TRAVERSE ( & dial - > channels , channel , list ) {
if ( channel - > owner = = owner )
break ;
}
2008-02-28 20:14:04 +00:00
AST_LIST_UNLOCK ( & dial - > channels ) ;
2007-01-24 18:23:07 +00:00
return channel ;
}
2007-02-12 18:01:15 +00:00
static void set_state ( struct ast_dial * dial , enum ast_dial_result state )
{
dial - > state = state ;
if ( dial - > state_callback )
dial - > state_callback ( dial ) ;
}
2007-01-24 18:23:07 +00:00
/*! \brief Helper function that handles control frames WITH owner */
static void handle_frame ( struct ast_dial * dial , struct ast_dial_channel * channel , struct ast_frame * fr , struct ast_channel * chan )
{
if ( fr - > frametype = = AST_FRAME_CONTROL ) {
switch ( fr - > subclass ) {
case AST_CONTROL_ANSWER :
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " %s answered %s \n " , channel - > owner - > name , chan - > name ) ;
2008-02-28 20:14:04 +00:00
AST_LIST_LOCK ( & dial - > channels ) ;
2007-01-24 18:23:07 +00:00
AST_LIST_REMOVE ( & dial - > channels , channel , list ) ;
AST_LIST_INSERT_HEAD ( & dial - > channels , channel , list ) ;
2008-02-28 20:14:04 +00:00
AST_LIST_UNLOCK ( & dial - > channels ) ;
2007-02-12 18:01:15 +00:00
set_state ( dial , AST_DIAL_RESULT_ANSWERED ) ;
2007-01-24 18:23:07 +00:00
break ;
case AST_CONTROL_BUSY :
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " %s is busy \n " , channel - > owner - > name ) ;
2007-01-24 18:23:07 +00:00
ast_hangup ( channel - > owner ) ;
channel - > owner = NULL ;
break ;
case AST_CONTROL_CONGESTION :
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " %s is circuit-busy \n " , channel - > owner - > name ) ;
2007-01-24 18:23:07 +00:00
ast_hangup ( channel - > owner ) ;
channel - > owner = NULL ;
break ;
case AST_CONTROL_RINGING :
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " %s is ringing \n " , channel - > owner - > name ) ;
2007-04-10 19:16:24 +00:00
if ( ! dial - > options [ AST_DIAL_OPTION_MUSIC ] )
ast_indicate ( chan , AST_CONTROL_RINGING ) ;
2007-04-24 16:17:36 +00:00
set_state ( dial , AST_DIAL_RESULT_RINGING ) ;
2007-01-24 18:23:07 +00:00
break ;
case AST_CONTROL_PROGRESS :
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " %s is making progress, passing it to %s \n " , channel - > owner - > name , chan - > name ) ;
2007-01-24 18:23:07 +00:00
ast_indicate ( chan , AST_CONTROL_PROGRESS ) ;
2007-04-24 16:17:36 +00:00
set_state ( dial , AST_DIAL_RESULT_PROGRESS ) ;
2007-01-24 18:23:07 +00:00
break ;
case AST_CONTROL_VIDUPDATE :
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " %s requested a video update, passing it to %s \n " , channel - > owner - > name , chan - > name ) ;
2007-01-24 18:23:07 +00:00
ast_indicate ( chan , AST_CONTROL_VIDUPDATE ) ;
break ;
2008-03-05 22:43:22 +00:00
case AST_CONTROL_SRCUPDATE :
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " %s requested a source update, passing it to %s \n " , channel - > owner - > name , chan - > name ) ;
ast_indicate ( chan , AST_CONTROL_SRCUPDATE ) ;
2008-03-16 21:50:58 +00:00
break ;
2007-01-24 18:23:07 +00:00
case AST_CONTROL_PROCEEDING :
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " %s is proceeding, passing it to %s \n " , channel - > owner - > name , chan - > name ) ;
2007-01-24 18:23:07 +00:00
ast_indicate ( chan , AST_CONTROL_PROCEEDING ) ;
2007-04-24 16:17:36 +00:00
set_state ( dial , AST_DIAL_RESULT_PROCEEDING ) ;
2007-01-24 18:23:07 +00:00
break ;
case AST_CONTROL_HOLD :
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Call on %s placed on hold \n " , chan - > name ) ;
2007-01-24 18:23:07 +00:00
ast_indicate ( chan , AST_CONTROL_HOLD ) ;
break ;
case AST_CONTROL_UNHOLD :
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Call on %s left from hold \n " , chan - > name ) ;
2007-01-24 18:23:07 +00:00
ast_indicate ( chan , AST_CONTROL_UNHOLD ) ;
break ;
case AST_CONTROL_OFFHOOK :
case AST_CONTROL_FLASH :
break ;
case - 1 :
/* Prod the channel */
ast_indicate ( chan , - 1 ) ;
break ;
default :
break ;
}
}
return ;
}
/*! \brief Helper function that handles control frames WITHOUT owner */
static void handle_frame_ownerless ( struct ast_dial * dial , struct ast_dial_channel * channel , struct ast_frame * fr )
{
2007-02-12 18:01:15 +00:00
/* If we have no owner we can only update the state of the dial structure, so only look at control frames */
2007-01-24 18:23:07 +00:00
if ( fr - > frametype ! = AST_FRAME_CONTROL )
return ;
switch ( fr - > subclass ) {
case AST_CONTROL_ANSWER :
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " %s answered \n " , channel - > owner - > name ) ;
2008-02-28 20:14:04 +00:00
AST_LIST_LOCK ( & dial - > channels ) ;
2007-01-24 18:23:07 +00:00
AST_LIST_REMOVE ( & dial - > channels , channel , list ) ;
AST_LIST_INSERT_HEAD ( & dial - > channels , channel , list ) ;
2008-02-28 20:14:04 +00:00
AST_LIST_UNLOCK ( & dial - > channels ) ;
2007-02-12 18:01:15 +00:00
set_state ( dial , AST_DIAL_RESULT_ANSWERED ) ;
2007-01-24 18:23:07 +00:00
break ;
case AST_CONTROL_BUSY :
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " %s is busy \n " , channel - > owner - > name ) ;
2007-01-24 18:23:07 +00:00
ast_hangup ( channel - > owner ) ;
channel - > owner = NULL ;
break ;
case AST_CONTROL_CONGESTION :
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " %s is circuit-busy \n " , channel - > owner - > name ) ;
2007-01-24 18:23:07 +00:00
ast_hangup ( channel - > owner ) ;
channel - > owner = NULL ;
break ;
case AST_CONTROL_RINGING :
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " %s is ringing \n " , channel - > owner - > name ) ;
2007-02-12 18:01:15 +00:00
set_state ( dial , AST_DIAL_RESULT_RINGING ) ;
2007-01-24 18:23:07 +00:00
break ;
case AST_CONTROL_PROGRESS :
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " %s is making progress \n " , channel - > owner - > name ) ;
2007-02-12 18:01:15 +00:00
set_state ( dial , AST_DIAL_RESULT_PROGRESS ) ;
2007-01-24 18:23:07 +00:00
break ;
case AST_CONTROL_PROCEEDING :
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " %s is proceeding \n " , channel - > owner - > name ) ;
2007-02-12 18:01:15 +00:00
set_state ( dial , AST_DIAL_RESULT_PROCEEDING ) ;
2007-01-24 18:23:07 +00:00
break ;
default :
break ;
}
return ;
}
2007-07-30 20:42:28 +00:00
/*! \brief Helper function to handle when a timeout occurs on dialing attempt */
static int handle_timeout_trip ( struct ast_dial * dial , struct timeval start )
{
struct ast_dial_channel * channel = NULL ;
int diff = ast_tvdiff_ms ( ast_tvnow ( ) , start ) , lowest_timeout = - 1 , new_timeout = - 1 ;
/* If the global dial timeout tripped switch the state to timeout so our channel loop will drop every channel */
if ( diff > = dial - > timeout ) {
set_state ( dial , AST_DIAL_RESULT_TIMEOUT ) ;
new_timeout = 0 ;
}
/* Go through dropping out channels that have met their timeout */
AST_LIST_TRAVERSE ( & dial - > channels , channel , list ) {
if ( dial - > state = = AST_DIAL_RESULT_TIMEOUT | | diff > = channel - > timeout ) {
ast_hangup ( channel - > owner ) ;
channel - > owner = NULL ;
} else if ( ( lowest_timeout = = - 1 ) | | ( lowest_timeout > channel - > timeout ) ) {
lowest_timeout = channel - > timeout ;
}
}
/* Calculate the new timeout using the lowest timeout found */
if ( lowest_timeout > = 0 )
new_timeout = lowest_timeout - diff ;
return new_timeout ;
}
2007-01-24 18:23:07 +00:00
/*! \brief Helper function that basically keeps tabs on dialing attempts */
static enum ast_dial_result monitor_dial ( struct ast_dial * dial , struct ast_channel * chan )
{
2007-07-30 20:42:28 +00:00
int timeout = - 1 ;
2007-01-24 18:23:07 +00:00
struct ast_channel * cs [ AST_MAX_WATCHERS ] , * who = NULL ;
struct ast_dial_channel * channel = NULL ;
struct answer_exec_struct * answer_exec = NULL ;
2007-07-30 20:42:28 +00:00
struct timeval start ;
2007-01-24 18:23:07 +00:00
2007-02-12 18:01:15 +00:00
set_state ( dial , AST_DIAL_RESULT_TRYING ) ;
2007-01-24 18:23:07 +00:00
2007-02-12 18:01:15 +00:00
/* If the "always indicate ringing" option is set, change state to ringing and indicate to the owner if present */
2007-01-24 18:23:07 +00:00
if ( dial - > options [ AST_DIAL_OPTION_RINGING ] ) {
2007-02-12 18:01:15 +00:00
set_state ( dial , AST_DIAL_RESULT_RINGING ) ;
2007-01-24 18:23:07 +00:00
if ( chan )
ast_indicate ( chan , AST_CONTROL_RINGING ) ;
2007-04-10 19:16:24 +00:00
} else if ( chan & & dial - > options [ AST_DIAL_OPTION_MUSIC ] & &
! ast_strlen_zero ( dial - > options [ AST_DIAL_OPTION_MUSIC ] ) ) {
char * original_moh = ast_strdupa ( chan - > musicclass ) ;
ast_indicate ( chan , - 1 ) ;
ast_string_field_set ( chan , musicclass , dial - > options [ AST_DIAL_OPTION_MUSIC ] ) ;
ast_moh_start ( chan , dial - > options [ AST_DIAL_OPTION_MUSIC ] , NULL ) ;
ast_string_field_set ( chan , musicclass , original_moh ) ;
2007-01-24 18:23:07 +00:00
}
2007-07-30 20:42:28 +00:00
/* Record start time for timeout purposes */
start = ast_tvnow ( ) ;
/* We actually figured out the maximum timeout we can do as they were added, so we can directly access the info */
timeout = dial - > actual_timeout ;
2007-01-24 18:23:07 +00:00
/* Go into an infinite loop while we are trying */
2007-02-12 18:01:15 +00:00
while ( ( dial - > state ! = AST_DIAL_RESULT_UNANSWERED ) & & ( dial - > state ! = AST_DIAL_RESULT_ANSWERED ) & & ( dial - > state ! = AST_DIAL_RESULT_HANGUP ) & & ( dial - > state ! = AST_DIAL_RESULT_TIMEOUT ) ) {
2007-07-30 20:42:28 +00:00
int pos = 0 , count = 0 ;
2007-01-24 18:23:07 +00:00
struct ast_frame * fr = NULL ;
/* Set up channel structure array */
pos = count = 0 ;
if ( chan )
cs [ pos + + ] = chan ;
/* Add channels we are attempting to dial */
2008-02-28 20:14:04 +00:00
AST_LIST_LOCK ( & dial - > channels ) ;
2007-01-24 18:23:07 +00:00
AST_LIST_TRAVERSE ( & dial - > channels , channel , list ) {
if ( channel - > owner ) {
cs [ pos + + ] = channel - > owner ;
count + + ;
}
}
2008-02-28 20:14:04 +00:00
AST_LIST_UNLOCK ( & dial - > channels ) ;
2007-01-24 18:23:07 +00:00
2007-02-12 18:01:15 +00:00
/* If we have no outbound channels in progress, switch state to unanswered and stop */
2007-01-24 18:23:07 +00:00
if ( ! count ) {
2007-02-12 18:01:15 +00:00
set_state ( dial , AST_DIAL_RESULT_UNANSWERED ) ;
2007-01-24 18:23:07 +00:00
break ;
}
/* Just to be safe... */
if ( dial - > thread = = AST_PTHREADT_STOP )
break ;
/* Wait for frames from channels */
who = ast_waitfor_n ( cs , pos , & timeout ) ;
/* Check to see if our thread is being cancelled */
if ( dial - > thread = = AST_PTHREADT_STOP )
break ;
2007-07-30 20:42:28 +00:00
/* If the timeout no longer exists OR if we got no channel it basically means the timeout was tripped, so handle it */
if ( ! timeout | | ! who ) {
timeout = handle_timeout_trip ( dial , start ) ;
2007-01-24 18:23:07 +00:00
continue ;
2007-07-30 20:42:28 +00:00
}
2007-01-24 18:23:07 +00:00
/* Find relative dial channel */
if ( ! chan | | ! IS_CALLER ( chan , who ) )
channel = find_relative_dial_channel ( dial , who ) ;
2007-07-30 20:42:28 +00:00
/* See if this channel has been forwarded elsewhere */
if ( ! ast_strlen_zero ( who - > call_forward ) ) {
handle_call_forward ( dial , channel , chan ) ;
continue ;
}
2007-01-24 18:23:07 +00:00
/* Attempt to read in a frame */
if ( ! ( fr = ast_read ( who ) ) ) {
2007-02-12 18:01:15 +00:00
/* If this is the caller then we switch state to hangup and stop */
2007-01-24 18:23:07 +00:00
if ( chan & & IS_CALLER ( chan , who ) ) {
2007-02-12 18:01:15 +00:00
set_state ( dial , AST_DIAL_RESULT_HANGUP ) ;
2007-01-24 18:23:07 +00:00
break ;
}
2007-08-10 18:37:32 +00:00
if ( chan )
ast_poll_channel_del ( chan , channel - > owner ) ;
2007-01-24 18:23:07 +00:00
ast_hangup ( who ) ;
channel - > owner = NULL ;
continue ;
}
/* Process the frame */
if ( chan )
handle_frame ( dial , channel , fr , chan ) ;
else
handle_frame_ownerless ( dial , channel , fr ) ;
/* Free the received frame and start all over */
ast_frfree ( fr ) ;
}
/* Do post-processing from loop */
2007-02-12 18:01:15 +00:00
if ( dial - > state = = AST_DIAL_RESULT_ANSWERED ) {
2007-01-24 18:23:07 +00:00
/* Hangup everything except that which answered */
2008-02-28 20:14:04 +00:00
AST_LIST_LOCK ( & dial - > channels ) ;
2007-01-24 18:23:07 +00:00
AST_LIST_TRAVERSE ( & dial - > channels , channel , list ) {
if ( ! channel - > owner | | channel - > owner = = who )
continue ;
2007-08-10 18:37:32 +00:00
if ( chan )
ast_poll_channel_del ( chan , channel - > owner ) ;
2007-01-24 18:23:07 +00:00
ast_hangup ( channel - > owner ) ;
channel - > owner = NULL ;
}
2008-02-28 20:14:04 +00:00
AST_LIST_UNLOCK ( & dial - > channels ) ;
2007-01-24 18:23:07 +00:00
/* If ANSWER_EXEC is enabled as an option, execute application on answered channel */
2007-11-26 21:14:07 +00:00
if ( ( channel = find_relative_dial_channel ( dial , who ) ) & & ( answer_exec = FIND_RELATIVE_OPTION ( dial , channel , AST_DIAL_OPTION_ANSWER_EXEC ) ) ) {
channel - > is_running_app = 1 ;
answer_exec_run ( dial , channel , answer_exec - > app , answer_exec - > args ) ;
channel - > is_running_app = 0 ;
}
2007-04-10 19:16:24 +00:00
if ( chan & & dial - > options [ AST_DIAL_OPTION_MUSIC ] & &
! ast_strlen_zero ( dial - > options [ AST_DIAL_OPTION_MUSIC ] ) ) {
ast_moh_stop ( chan ) ;
}
2007-02-12 18:01:15 +00:00
} else if ( dial - > state = = AST_DIAL_RESULT_HANGUP ) {
2007-01-24 18:23:07 +00:00
/* Hangup everything */
2008-02-28 20:14:04 +00:00
AST_LIST_LOCK ( & dial - > channels ) ;
2007-01-24 18:23:07 +00:00
AST_LIST_TRAVERSE ( & dial - > channels , channel , list ) {
if ( ! channel - > owner )
continue ;
2007-08-10 18:37:32 +00:00
if ( chan )
ast_poll_channel_del ( chan , channel - > owner ) ;
2007-01-24 18:23:07 +00:00
ast_hangup ( channel - > owner ) ;
channel - > owner = NULL ;
}
2008-02-28 20:14:04 +00:00
AST_LIST_UNLOCK ( & dial - > channels ) ;
2007-01-24 18:23:07 +00:00
}
2007-02-12 18:01:15 +00:00
return dial - > state ;
2007-01-24 18:23:07 +00:00
}
/*! \brief Dial async thread function */
static void * async_dial ( void * data )
{
struct ast_dial * dial = data ;
/* This is really really simple... we basically pass monitor_dial a NULL owner and it changes it's behavior */
monitor_dial ( dial , NULL ) ;
return NULL ;
}
/*! \brief Execute dialing synchronously or asynchronously
* \ note Dials channels in a dial structure .
* \ return Returns dial result code . ( TRYING / INVALID / FAILED / ANSWERED / TIMEOUT / UNANSWERED ) .
*/
enum ast_dial_result ast_dial_run ( struct ast_dial * dial , struct ast_channel * chan , int async )
{
enum ast_dial_result res = AST_DIAL_RESULT_TRYING ;
/* Ensure required arguments are passed */
2007-02-10 00:40:57 +00:00
if ( ! dial | | ( ! chan & & ! async ) ) {
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , " invalid #1 \n " ) ;
2007-01-24 18:23:07 +00:00
return AST_DIAL_RESULT_INVALID ;
2007-02-10 00:40:57 +00:00
}
2007-01-24 18:23:07 +00:00
/* If there are no channels to dial we can't very well try to dial them */
2007-02-10 00:40:57 +00:00
if ( AST_LIST_EMPTY ( & dial - > channels ) ) {
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , " invalid #2 \n " ) ;
2007-01-24 18:23:07 +00:00
return AST_DIAL_RESULT_INVALID ;
2007-02-10 00:40:57 +00:00
}
2007-01-24 18:23:07 +00:00
/* Dial each requested channel */
if ( ! begin_dial ( dial , chan ) )
return AST_DIAL_RESULT_FAILED ;
/* If we are running async spawn a thread and send it away... otherwise block here */
if ( async ) {
2007-02-22 23:12:26 +00:00
dial - > state = AST_DIAL_RESULT_TRYING ;
2007-01-24 18:23:07 +00:00
/* Try to create a thread */
if ( ast_pthread_create ( & dial - > thread , NULL , async_dial , dial ) ) {
/* Failed to create the thread - hangup all dialed channels and return failed */
ast_dial_hangup ( dial ) ;
res = AST_DIAL_RESULT_FAILED ;
}
} else {
res = monitor_dial ( dial , chan ) ;
}
return res ;
}
/*! \brief Return channel that answered
* \ note Returns the Asterisk channel that answered
* \ param dial Dialing structure
*/
struct ast_channel * ast_dial_answered ( struct ast_dial * dial )
{
if ( ! dial )
return NULL ;
2007-02-12 18:01:15 +00:00
return ( ( dial - > state = = AST_DIAL_RESULT_ANSWERED ) ? AST_LIST_FIRST ( & dial - > channels ) - > owner : NULL ) ;
2007-01-24 18:23:07 +00:00
}
2008-01-25 02:52:10 +00:00
/*! \brief Steal the channel that answered
* \ note Returns the Asterisk channel that answered and removes it from the dialing structure
* \ param dial Dialing structure
*/
struct ast_channel * ast_dial_answered_steal ( struct ast_dial * dial )
{
struct ast_channel * chan = NULL ;
if ( ! dial )
return NULL ;
if ( dial - > state = = AST_DIAL_RESULT_ANSWERED ) {
chan = AST_LIST_FIRST ( & dial - > channels ) - > owner ;
AST_LIST_FIRST ( & dial - > channels ) - > owner = NULL ;
}
return chan ;
}
2007-02-12 18:01:15 +00:00
/*! \brief Return state of dial
* \ note Returns the state of the dial attempt
2007-01-24 18:23:07 +00:00
* \ param dial Dialing structure
*/
2007-02-12 18:01:15 +00:00
enum ast_dial_result ast_dial_state ( struct ast_dial * dial )
2007-01-24 18:23:07 +00:00
{
2007-02-12 18:01:15 +00:00
return dial - > state ;
2007-01-24 18:23:07 +00:00
}
/*! \brief Cancel async thread
* \ note Cancel a running async thread
* \ param dial Dialing structure
*/
enum ast_dial_result ast_dial_join ( struct ast_dial * dial )
{
pthread_t thread ;
/* If the dial structure is not running in async, return failed */
if ( dial - > thread = = AST_PTHREADT_NULL )
return AST_DIAL_RESULT_FAILED ;
/* Record thread */
thread = dial - > thread ;
2008-01-16 15:09:37 +00:00
/* Boom, commence locking */
ast_mutex_lock ( & dial - > lock ) ;
2007-01-24 18:23:07 +00:00
/* Stop the thread */
dial - > thread = AST_PTHREADT_STOP ;
2007-11-26 21:14:07 +00:00
/* If the answered channel is running an application we have to soft hangup it, can't just poke the thread */
2008-02-28 20:14:04 +00:00
AST_LIST_LOCK ( & dial - > channels ) ;
2007-11-26 21:14:07 +00:00
if ( AST_LIST_FIRST ( & dial - > channels ) - > is_running_app ) {
struct ast_channel * chan = AST_LIST_FIRST ( & dial - > channels ) - > owner ;
2008-02-28 20:14:04 +00:00
if ( chan ) {
ast_channel_lock ( chan ) ;
ast_softhangup ( chan , AST_SOFTHANGUP_EXPLICIT ) ;
ast_channel_unlock ( chan ) ;
}
2007-11-26 21:14:07 +00:00
} else {
/* Now we signal it with SIGURG so it will break out of it's waitfor */
pthread_kill ( thread , SIGURG ) ;
}
2008-02-28 20:14:04 +00:00
AST_LIST_UNLOCK ( & dial - > channels ) ;
2007-01-24 18:23:07 +00:00
2008-01-16 15:09:37 +00:00
/* Yay done with it */
ast_mutex_unlock ( & dial - > lock ) ;
2007-01-24 18:23:07 +00:00
/* Finally wait for the thread to exit */
pthread_join ( thread , NULL ) ;
/* Yay thread is all gone */
dial - > thread = AST_PTHREADT_NULL ;
2007-02-12 18:01:15 +00:00
return dial - > state ;
2007-01-24 18:23:07 +00:00
}
/*! \brief Hangup channels
* \ note Hangup all active channels
* \ param dial Dialing structure
*/
void ast_dial_hangup ( struct ast_dial * dial )
{
struct ast_dial_channel * channel = NULL ;
if ( ! dial )
return ;
2008-02-28 20:14:04 +00:00
AST_LIST_LOCK ( & dial - > channels ) ;
2007-01-24 18:23:07 +00:00
AST_LIST_TRAVERSE ( & dial - > channels , channel , list ) {
if ( channel - > owner ) {
ast_hangup ( channel - > owner ) ;
channel - > owner = NULL ;
}
}
2008-02-28 20:14:04 +00:00
AST_LIST_UNLOCK ( & dial - > channels ) ;
2007-01-24 18:23:07 +00:00
return ;
}
/*! \brief Destroys a dialing structure
* \ note Destroys ( free ' s ) the given ast_dial structure
* \ param dial Dialing structure to free
* \ return Returns 0 on success , - 1 on failure
*/
int ast_dial_destroy ( struct ast_dial * dial )
{
int i = 0 ;
struct ast_dial_channel * channel = NULL ;
if ( ! dial )
return - 1 ;
/* Hangup and deallocate all the dialed channels */
2008-02-28 20:14:04 +00:00
AST_LIST_LOCK ( & dial - > channels ) ;
2007-12-21 16:52:04 +00:00
AST_LIST_TRAVERSE_SAFE_BEGIN ( & dial - > channels , channel , list ) {
2007-01-24 18:23:07 +00:00
/* Disable any enabled options */
for ( i = 0 ; i < AST_DIAL_OPTION_MAX ; i + + ) {
if ( ! channel - > options [ i ] )
continue ;
if ( option_types [ i ] . disable )
option_types [ i ] . disable ( channel - > options [ i ] ) ;
channel - > options [ i ] = NULL ;
}
/* Hang up channel if need be */
if ( channel - > owner ) {
ast_hangup ( channel - > owner ) ;
channel - > owner = NULL ;
}
/* Free structure */
2007-07-30 20:42:28 +00:00
ast_free ( channel - > tech ) ;
ast_free ( channel - > device ) ;
2007-12-21 17:40:44 +00:00
AST_LIST_REMOVE_CURRENT ( list ) ;
2007-06-06 21:20:11 +00:00
ast_free ( channel ) ;
2007-01-24 18:23:07 +00:00
}
2007-12-21 16:52:04 +00:00
AST_LIST_TRAVERSE_SAFE_END ;
2008-02-28 20:14:04 +00:00
AST_LIST_UNLOCK ( & dial - > channels ) ;
2008-03-04 23:04:29 +00:00
2007-01-24 18:23:07 +00:00
/* Disable any enabled options globally */
for ( i = 0 ; i < AST_DIAL_OPTION_MAX ; i + + ) {
if ( ! dial - > options [ i ] )
continue ;
if ( option_types [ i ] . disable )
option_types [ i ] . disable ( dial - > options [ i ] ) ;
dial - > options [ i ] = NULL ;
}
2008-01-16 15:09:37 +00:00
/* Lock be gone! */
ast_mutex_destroy ( & dial - > lock ) ;
2007-01-24 18:23:07 +00:00
/* Free structure */
2007-06-06 21:20:11 +00:00
ast_free ( dial ) ;
2007-01-24 18:23:07 +00:00
return 0 ;
}
/*! \brief Enables an option globally
* \ param dial Dial structure to enable option on
* \ param option Option to enable
* \ param data Data to pass to this option ( not always needed )
* \ return Returns 0 on success , - 1 on failure
*/
int ast_dial_option_global_enable ( struct ast_dial * dial , enum ast_dial_option option , void * data )
{
/* If the option is already enabled, return failure */
if ( dial - > options [ option ] )
return - 1 ;
/* Execute enable callback if it exists, if not simply make sure the value is set */
if ( option_types [ option ] . enable )
dial - > options [ option ] = option_types [ option ] . enable ( data ) ;
else
dial - > options [ option ] = ( void * ) 1 ;
return 0 ;
}
2007-07-30 20:42:28 +00:00
/*! \brief Helper function for finding a channel in a dial structure based on number
*/
static struct ast_dial_channel * find_dial_channel ( struct ast_dial * dial , int num )
{
struct ast_dial_channel * channel = AST_LIST_LAST ( & dial - > channels ) ;
/* We can try to predict programmer behavior, the last channel they added is probably the one they wanted to modify */
if ( channel - > num = = num )
return channel ;
/* Hrm not at the end... looking through the list it is! */
2008-02-28 20:14:04 +00:00
AST_LIST_LOCK ( & dial - > channels ) ;
2007-07-30 20:42:28 +00:00
AST_LIST_TRAVERSE ( & dial - > channels , channel , list ) {
if ( channel - > num = = num )
break ;
}
2008-02-28 20:14:04 +00:00
AST_LIST_UNLOCK ( & dial - > channels ) ;
2007-07-30 20:42:28 +00:00
return channel ;
}
2007-01-24 18:23:07 +00:00
/*! \brief Enables an option per channel
* \ param dial Dial structure
* \ param num Channel number to enable option on
* \ param option Option to enable
* \ param data Data to pass to this option ( not always needed )
* \ return Returns 0 on success , - 1 on failure
*/
int ast_dial_option_enable ( struct ast_dial * dial , int num , enum ast_dial_option option , void * data )
{
struct ast_dial_channel * channel = NULL ;
/* Ensure we have required arguments */
if ( ! dial | | AST_LIST_EMPTY ( & dial - > channels ) )
return - 1 ;
2007-07-30 20:42:28 +00:00
if ( ! ( channel = find_dial_channel ( dial , num ) ) )
2007-01-24 18:23:07 +00:00
return - 1 ;
/* If the option is already enabled, return failure */
if ( channel - > options [ option ] )
return - 1 ;
2008-03-04 23:04:29 +00:00
/* Execute enable callback if it exists, if not simply make sure the value is set */
2007-01-24 18:23:07 +00:00
if ( option_types [ option ] . enable )
channel - > options [ option ] = option_types [ option ] . enable ( data ) ;
else
channel - > options [ option ] = ( void * ) 1 ;
return 0 ;
}
/*! \brief Disables an option globally
* \ param dial Dial structure to disable option on
* \ param option Option to disable
* \ return Returns 0 on success , - 1 on failure
*/
int ast_dial_option_global_disable ( struct ast_dial * dial , enum ast_dial_option option )
{
2008-03-04 23:04:29 +00:00
/* If the option is not enabled, return failure */
if ( ! dial - > options [ option ] ) {
return - 1 ;
}
2007-01-24 18:23:07 +00:00
/* Execute callback of option to disable if it exists */
if ( option_types [ option ] . disable )
option_types [ option ] . disable ( dial - > options [ option ] ) ;
/* Finally disable option on the structure */
dial - > options [ option ] = NULL ;
2008-03-04 23:04:29 +00:00
return 0 ;
2007-01-24 18:23:07 +00:00
}
/*! \brief Disables an option per channel
* \ param dial Dial structure
* \ param num Channel number to disable option on
* \ param option Option to disable
* \ return Returns 0 on success , - 1 on failure
*/
int ast_dial_option_disable ( struct ast_dial * dial , int num , enum ast_dial_option option )
{
struct ast_dial_channel * channel = NULL ;
/* Ensure we have required arguments */
if ( ! dial | | AST_LIST_EMPTY ( & dial - > channels ) )
return - 1 ;
2007-07-30 20:42:28 +00:00
if ( ! ( channel = find_dial_channel ( dial , num ) ) )
2007-01-24 18:23:07 +00:00
return - 1 ;
/* If the option is not enabled, return failure */
if ( ! channel - > options [ option ] )
return - 1 ;
/* Execute callback of option to disable it if it exists */
if ( option_types [ option ] . disable )
option_types [ option ] . disable ( channel - > options [ option ] ) ;
/* Finally disable the option on the structure */
channel - > options [ option ] = NULL ;
return 0 ;
}
2007-02-12 18:01:15 +00:00
2007-02-12 19:18:33 +00:00
void ast_dial_set_state_callback ( struct ast_dial * dial , ast_dial_state_callback callback )
2007-02-12 18:01:15 +00:00
{
dial - > state_callback = callback ;
}
2007-07-30 20:42:28 +00:00
/*! \brief Set the maximum time (globally) allowed for trying to ring phones
* \ param dial The dial structure to apply the time limit to
* \ param timeout Maximum time allowed
* \ return nothing
*/
void ast_dial_set_global_timeout ( struct ast_dial * dial , int timeout )
{
dial - > timeout = timeout ;
2008-10-31 20:05:46 +00:00
if ( dial - > timeout > 0 & & ( dial - > actual_timeout > dial - > timeout | | dial - > actual_timeout = = - 1 ) )
2007-07-30 20:42:28 +00:00
dial - > actual_timeout = dial - > timeout ;
return ;
}
/*! \brief Set the maximum time (per channel) allowed for trying to ring the phone
* \ param dial The dial structure the channel belongs to
* \ param num Channel number to set timeout on
* \ param timeout Maximum time allowed
* \ return nothing
*/
void ast_dial_set_timeout ( struct ast_dial * dial , int num , int timeout )
{
struct ast_dial_channel * channel = NULL ;
if ( ! ( channel = find_dial_channel ( dial , num ) ) )
return ;
channel - > timeout = timeout ;
2008-10-31 20:05:46 +00:00
if ( channel - > timeout > 0 & & ( dial - > actual_timeout > channel - > timeout | | dial - > actual_timeout = = - 1 ) )
2007-07-30 20:42:28 +00:00
dial - > actual_timeout = channel - > timeout ;
return ;
}