Dialing API. More...
#include "asterisk.h"
#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"
#include "asterisk/musiconhold.h"
Go to the source code of this file.
Data Structures | |
struct | answer_exec_struct |
Structure for 'ANSWER_EXEC' option. More... | |
struct | ast_dial |
Main dialing structure. Contains global options, channels being dialed, and more! More... | |
struct | ast_dial_channel |
Dialing channel structure. Contains per-channel dialing options, asterisk channel, and more! More... | |
struct | ast_option_types |
Options structure - maps options to respective handlers (enable/disable). This list MUST be perfectly kept in order, or else madness will happen. More... | |
Defines | |
#define | AST_MAX_WATCHERS 256 |
Maximum number of channels we can watch at a time. | |
#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]) |
Macro for finding the option structure to use on a dialed channel. | |
#define | IS_CALLER(chan, owner) (chan == owner ? 1 : 0) |
Macro that determines whether a channel is the caller or not. | |
#define | S_REPLACE(s, new_val) |
free the buffer if allocated, and set the pointer to the second arg | |
Typedefs | |
typedef int(* | ast_dial_option_cb_disable )(void *data) |
Typedef for dial option disable. | |
typedef void *(* | ast_dial_option_cb_enable )(void *data) |
Typedef for dial option enable. | |
Functions | |
static int | answer_exec_disable (void *data) |
Disable function for 'ANSWER_EXEC' option. | |
static void * | answer_exec_enable (void *data) |
Enable function for 'ANSWER_EXEC' option. | |
static void | answer_exec_run (struct ast_dial *dial, struct ast_dial_channel *dial_channel, char *app, char *args) |
Application execution function for 'ANSWER_EXEC' option. | |
struct ast_channel * | ast_dial_answered (struct ast_dial *dial) |
Return channel that answered. | |
struct ast_channel * | ast_dial_answered_steal (struct ast_dial *dial) |
Steal the channel that answered. | |
int | ast_dial_append (struct ast_dial *dial, const char *tech, const char *device) |
Append a channel. | |
struct ast_dial * | ast_dial_create (void) |
New dialing structure. | |
int | ast_dial_destroy (struct ast_dial *dial) |
Destroys a dialing structure. | |
void | ast_dial_hangup (struct ast_dial *dial) |
Hangup channels. | |
enum ast_dial_result | ast_dial_join (struct ast_dial *dial) |
Cancel async thread. | |
int | ast_dial_option_disable (struct ast_dial *dial, int num, enum ast_dial_option option) |
Disables an option per channel. | |
int | ast_dial_option_enable (struct ast_dial *dial, int num, enum ast_dial_option option, void *data) |
Enables an option per channel. | |
int | ast_dial_option_global_disable (struct ast_dial *dial, enum ast_dial_option option) |
Disables an option globally. | |
int | ast_dial_option_global_enable (struct ast_dial *dial, enum ast_dial_option option, void *data) |
Enables an option globally. | |
enum ast_dial_result | ast_dial_run (struct ast_dial *dial, struct ast_channel *chan, int async) |
Execute dialing synchronously or asynchronously. | |
void | ast_dial_set_global_timeout (struct ast_dial *dial, int timeout) |
Set the maximum time (globally) allowed for trying to ring phones. | |
void | ast_dial_set_state_callback (struct ast_dial *dial, ast_dial_state_callback callback) |
Set a callback for state changes. | |
void | ast_dial_set_timeout (struct ast_dial *dial, int num, int timeout) |
Set the maximum time (per channel) allowed for trying to ring the phone. | |
enum ast_dial_result | ast_dial_state (struct ast_dial *dial) |
Return state of dial. | |
static void * | async_dial (void *data) |
Dial async thread function. | |
static int | begin_dial (struct ast_dial *dial, struct ast_channel *chan) |
Helper function that does the beginning dialing per dial structure. | |
static int | begin_dial_channel (struct ast_dial_channel *channel, struct ast_channel *chan) |
Helper function that does the beginning dialing per-appended channel. | |
static struct ast_dial_channel * | find_dial_channel (struct ast_dial *dial, int num) |
Helper function for finding a channel in a dial structure based on number. | |
static struct ast_dial_channel * | find_relative_dial_channel (struct ast_dial *dial, struct ast_channel *owner) |
Helper function that finds the dialed channel based on owner. | |
static int | handle_call_forward (struct ast_dial *dial, struct ast_dial_channel *channel, struct ast_channel *chan) |
Helper function to handle channels that have been call forwarded. | |
static void | handle_frame (struct ast_dial *dial, struct ast_dial_channel *channel, struct ast_frame *fr, struct ast_channel *chan) |
Helper function that handles control frames WITH owner. | |
static void | handle_frame_ownerless (struct ast_dial *dial, struct ast_dial_channel *channel, struct ast_frame *fr) |
Helper function that handles control frames WITHOUT owner. | |
static int | handle_timeout_trip (struct ast_dial *dial, struct timeval start) |
Helper function to handle when a timeout occurs on dialing attempt. | |
static enum ast_dial_result | monitor_dial (struct ast_dial *dial, struct ast_channel *chan) |
Helper function that basically keeps tabs on dialing attempts. | |
static int | music_disable (void *data) |
static void * | music_enable (void *data) |
static void | set_state (struct ast_dial *dial, enum ast_dial_result state) |
Variables | |
static struct ast_option_types | option_types [] |
Dialing API.
Definition in file dial.c.
#define AST_MAX_WATCHERS 256 |
Maximum number of channels we can watch at a time.
Definition at line 186 of file dial.c.
Referenced by monitor_dial().
#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]) |
Macro for finding the option structure to use on a dialed channel.
Definition at line 189 of file dial.c.
Referenced by handle_call_forward(), and monitor_dial().
Macro that determines whether a channel is the caller or not.
Definition at line 192 of file dial.c.
Referenced by monitor_dial().
#define S_REPLACE | ( | s, | |
new_val | |||
) |
free the buffer if allocated, and set the pointer to the second arg
Definition at line 177 of file dial.c.
Referenced by begin_dial_channel().
typedef int(* ast_dial_option_cb_disable)(void *data) |
typedef void*(* ast_dial_option_cb_enable)(void *data) |
static int answer_exec_disable | ( | void * | data | ) | [static] |
Disable function for 'ANSWER_EXEC' option.
Definition at line 106 of file dial.c.
References answer_exec_struct::args, and ast_free.
{ 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) ast_free(answer_exec->args); /* This is simple - just free the structure */ ast_free(answer_exec); return 0; }
static void* answer_exec_enable | ( | void * | data | ) | [static] |
Enable function for 'ANSWER_EXEC' option.
Definition at line 80 of file dial.c.
References answer_exec_struct::app, app, answer_exec_struct::args, ast_calloc, ast_copy_string(), ast_strdup, ast_strdupa, and ast_strlen_zero().
{ 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 */ if ((args = strchr(app, ','))) { *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; }
static void answer_exec_run | ( | struct ast_dial * | dial, |
struct ast_dial_channel * | dial_channel, | ||
char * | app, | ||
char * | args | ||
) | [static] |
Application execution function for 'ANSWER_EXEC' option.
Definition at line 140 of file dial.c.
References ast_hangup(), ast_mutex_lock(), ast_mutex_unlock(), AST_PTHREADT_STOP, chan, ast_dial::lock, ast_dial_channel::owner, pbx_exec(), pbx_findapp(), and ast_dial::thread.
Referenced by monitor_dial().
{ struct ast_channel *chan = dial_channel->owner; 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); /* If another thread is not taking over hang up the channel */ ast_mutex_lock(&dial->lock); if (dial->thread != AST_PTHREADT_STOP) { ast_hangup(chan); dial_channel->owner = NULL; } ast_mutex_unlock(&dial->lock); return; }
struct ast_channel* ast_dial_answered | ( | struct ast_dial * | dial | ) | [read] |
Return channel that answered.
dial | Dialing structure |
Definition at line 738 of file dial.c.
References AST_DIAL_RESULT_ANSWERED, AST_LIST_FIRST, ast_dial::channels, and ast_dial::state.
Referenced by dial_trunk(), and sla_handle_dial_state_event().
{ if (!dial) return NULL; return ((dial->state == AST_DIAL_RESULT_ANSWERED) ? AST_LIST_FIRST(&dial->channels)->owner : NULL); }
struct ast_channel* ast_dial_answered_steal | ( | struct ast_dial * | dial | ) | [read] |
Steal the channel that answered.
dial | Dialing structure |
Definition at line 750 of file dial.c.
References AST_DIAL_RESULT_ANSWERED, AST_LIST_FIRST, chan, ast_dial::channels, and ast_dial::state.
{ 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; }
int ast_dial_append | ( | struct ast_dial * | dial, |
const char * | tech, | ||
const char * | device | ||
) |
Append a channel.
Definition at line 226 of file dial.c.
References ast_atomic_fetchadd_int(), ast_calloc, AST_LIST_INSERT_TAIL, ast_strdup, ast_dial::channels, ast_dial_channel::device, ast_dial_channel::list, ast_dial::num, ast_dial_channel::num, ast_dial_channel::tech, and ast_dial_channel::timeout.
Referenced by dial_trunk(), page_exec(), and sla_ring_station().
{ 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 */ channel->tech = ast_strdup(tech); channel->device = ast_strdup(device); /* Grab reference number from dial structure */ channel->num = ast_atomic_fetchadd_int(&dial->num, +1); /* No timeout exists... yet */ channel->timeout = -1; /* Insert into channels list */ AST_LIST_INSERT_TAIL(&dial->channels, channel, list); return channel->num; }
struct ast_dial* ast_dial_create | ( | void | ) | [read] |
New dialing structure.
Definition at line 198 of file dial.c.
References ast_dial::actual_timeout, ast_calloc, AST_LIST_HEAD_INIT, ast_mutex_init(), AST_PTHREADT_NULL, ast_dial::channels, ast_dial::lock, ast_dial::thread, and ast_dial::timeout.
Referenced by dial_trunk(), page_exec(), and sla_ring_station().
{ struct ast_dial *dial = NULL; /* Allocate new memory for structure */ if (!(dial = ast_calloc(1, sizeof(*dial)))) return NULL; /* Initialize list of channels */ AST_LIST_HEAD_INIT(&dial->channels); /* Initialize thread to NULL */ dial->thread = AST_PTHREADT_NULL; /* No timeout exists... yet */ dial->timeout = -1; dial->actual_timeout = -1; /* Can't forget about the lock */ ast_mutex_init(&dial->lock); return dial; }
int ast_dial_destroy | ( | struct ast_dial * | dial | ) |
Destroys a dialing structure.
dial | Dialing structure to free |
Definition at line 850 of file dial.c.
References AST_DIAL_OPTION_MAX, ast_free, ast_hangup(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_mutex_destroy(), ast_dial::channels, ast_dial_channel::device, ast_option_types::disable, ast_dial_channel::list, ast_dial::lock, option_types, ast_dial::options, ast_dial_channel::options, ast_dial_channel::owner, and ast_dial_channel::tech.
Referenced by dial_trunk(), page_exec(), run_station(), sla_hangup_stations(), sla_ring_station(), and sla_stop_ringing_station().
{ int i = 0; struct ast_dial_channel *channel = NULL; if (!dial) return -1; /* Hangup and deallocate all the dialed channels */ AST_LIST_LOCK(&dial->channels); AST_LIST_TRAVERSE_SAFE_BEGIN(&dial->channels, channel, list) { /* 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 */ ast_free(channel->tech); ast_free(channel->device); AST_LIST_REMOVE_CURRENT(list); ast_free(channel); } AST_LIST_TRAVERSE_SAFE_END; AST_LIST_UNLOCK(&dial->channels); /* 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; } /* Lock be gone! */ ast_mutex_destroy(&dial->lock); /* Free structure */ ast_free(dial); return 0; }
void ast_dial_hangup | ( | struct ast_dial * | dial | ) |
Hangup channels.
dial | Dialing structure |
Definition at line 826 of file dial.c.
References ast_hangup(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_dial::channels, ast_dial_channel::list, and ast_dial_channel::owner.
Referenced by ast_dial_run(), and page_exec().
{ struct ast_dial_channel *channel = NULL; if (!dial) return; AST_LIST_LOCK(&dial->channels); AST_LIST_TRAVERSE(&dial->channels, channel, list) { if (channel->owner) { ast_hangup(channel->owner); channel->owner = NULL; } } AST_LIST_UNLOCK(&dial->channels); return; }
enum ast_dial_result ast_dial_join | ( | struct ast_dial * | dial | ) |
Cancel async thread.
dial | Dialing structure |
Definition at line 778 of file dial.c.
References ast_channel_lock, ast_channel_unlock, AST_DIAL_RESULT_FAILED, AST_LIST_FIRST, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), AST_PTHREADT_NULL, AST_PTHREADT_STOP, ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, chan, ast_dial::channels, ast_dial::lock, ast_dial::state, and ast_dial::thread.
Referenced by dial_trunk(), page_exec(), run_station(), sla_hangup_stations(), sla_ring_station(), and sla_stop_ringing_station().
{ 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; /* Boom, commence locking */ ast_mutex_lock(&dial->lock); /* Stop the thread */ dial->thread = AST_PTHREADT_STOP; /* If the answered channel is running an application we have to soft hangup it, can't just poke the thread */ AST_LIST_LOCK(&dial->channels); if (AST_LIST_FIRST(&dial->channels)->is_running_app) { struct ast_channel *chan = AST_LIST_FIRST(&dial->channels)->owner; if (chan) { ast_channel_lock(chan); ast_softhangup(chan, AST_SOFTHANGUP_EXPLICIT); ast_channel_unlock(chan); } } else { /* Now we signal it with SIGURG so it will break out of it's waitfor */ pthread_kill(thread, SIGURG); } AST_LIST_UNLOCK(&dial->channels); /* Yay done with it */ ast_mutex_unlock(&dial->lock); /* Finally wait for the thread to exit */ pthread_join(thread, NULL); /* Yay thread is all gone */ dial->thread = AST_PTHREADT_NULL; return dial->state; }
int ast_dial_option_disable | ( | struct ast_dial * | dial, |
int | num, | ||
enum ast_dial_option | option | ||
) |
Disables an option per channel.
dial | Dial structure |
num | Channel number to disable option on |
option | Option to disable |
Definition at line 1002 of file dial.c.
References AST_LIST_EMPTY, ast_dial::channels, ast_option_types::disable, find_dial_channel(), option_types, and ast_dial_channel::options.
{ struct ast_dial_channel *channel = NULL; /* Ensure we have required arguments */ if (!dial || AST_LIST_EMPTY(&dial->channels)) return -1; if (!(channel = find_dial_channel(dial, num))) 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; }
int ast_dial_option_enable | ( | struct ast_dial * | dial, |
int | num, | ||
enum ast_dial_option | option, | ||
void * | data | ||
) |
Enables an option per channel.
dial | Dial structure |
num | Channel number to enable option on |
option | Option to enable |
data | Data to pass to this option (not always needed) |
Definition at line 950 of file dial.c.
References AST_LIST_EMPTY, ast_dial::channels, ast_option_types::enable, find_dial_channel(), option_types, and ast_dial_channel::options.
{ struct ast_dial_channel *channel = NULL; /* Ensure we have required arguments */ if (!dial || AST_LIST_EMPTY(&dial->channels)) return -1; if (!(channel = find_dial_channel(dial, num))) return -1; /* If the option is already enabled, return failure */ if (channel->options[option]) return -1; /* Execute enable callback if it exists, if not simply make sure the value is set */ if (option_types[option].enable) channel->options[option] = option_types[option].enable(data); else channel->options[option] = (void*)1; return 0; }
int ast_dial_option_global_disable | ( | struct ast_dial * | dial, |
enum ast_dial_option | option | ||
) |
Disables an option globally.
dial | Dial structure to disable option on |
option | Option to disable |
Definition at line 979 of file dial.c.
References ast_option_types::disable, option_types, and ast_dial::options.
{ /* If the option is not enabled, return failure */ if (!dial->options[option]) { return -1; } /* 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; return 0; }
int ast_dial_option_global_enable | ( | struct ast_dial * | dial, |
enum ast_dial_option | option, | ||
void * | data | ||
) |
Enables an option globally.
dial | Dial structure to enable option on |
option | Option to enable |
data | Data to pass to this option (not always needed) |
Definition at line 907 of file dial.c.
References ast_option_types::enable, option_types, and ast_dial::options.
Referenced by page_exec().
{ /* 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; }
enum ast_dial_result ast_dial_run | ( | struct ast_dial * | dial, |
struct ast_channel * | chan, | ||
int | async | ||
) |
Execute dialing synchronously or asynchronously.
Definition at line 698 of file dial.c.
References ast_debug, ast_dial_hangup(), AST_DIAL_RESULT_FAILED, AST_DIAL_RESULT_INVALID, AST_DIAL_RESULT_TRYING, AST_LIST_EMPTY, ast_pthread_create, async_dial(), begin_dial(), ast_dial::channels, monitor_dial(), ast_dial::state, and ast_dial::thread.
Referenced by dial_trunk(), page_exec(), and sla_ring_station().
{ enum ast_dial_result res = AST_DIAL_RESULT_TRYING; /* Ensure required arguments are passed */ if (!dial || (!chan && !async)) { ast_debug(1, "invalid #1\n"); return AST_DIAL_RESULT_INVALID; } /* If there are no channels to dial we can't very well try to dial them */ if (AST_LIST_EMPTY(&dial->channels)) { ast_debug(1, "invalid #2\n"); return AST_DIAL_RESULT_INVALID; } /* 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) { dial->state = AST_DIAL_RESULT_TRYING; /* 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; }
void ast_dial_set_global_timeout | ( | struct ast_dial * | dial, |
int | timeout | ||
) |
Set the maximum time (globally) allowed for trying to ring phones.
dial | The dial structure to apply the time limit to |
timeout | Maximum time allowed |
Definition at line 1037 of file dial.c.
References ast_dial::actual_timeout, and ast_dial::timeout.
Referenced by page_exec().
{ dial->timeout = timeout; if (dial->timeout > 0 && (dial->actual_timeout > dial->timeout || dial->actual_timeout == -1)) dial->actual_timeout = dial->timeout; return; }
void ast_dial_set_state_callback | ( | struct ast_dial * | dial, |
ast_dial_state_callback | callback | ||
) |
Set a callback for state changes.
dial | The dial structure to watch for state changes |
callback | the callback |
Definition at line 1027 of file dial.c.
References ast_dial::state_callback.
Referenced by sla_ring_station().
{ dial->state_callback = callback; }
void ast_dial_set_timeout | ( | struct ast_dial * | dial, |
int | num, | ||
int | timeout | ||
) |
Set the maximum time (per channel) allowed for trying to ring the phone.
dial | The dial structure the channel belongs to |
num | Channel number to set timeout on |
timeout | Maximum time allowed |
Definition at line 1053 of file dial.c.
References ast_dial::actual_timeout, find_dial_channel(), ast_dial::timeout, and ast_dial_channel::timeout.
{ struct ast_dial_channel *channel = NULL; if (!(channel = find_dial_channel(dial, num))) return; channel->timeout = timeout; if (channel->timeout > 0 && (dial->actual_timeout > channel->timeout || dial->actual_timeout == -1)) dial->actual_timeout = channel->timeout; return; }
enum ast_dial_result ast_dial_state | ( | struct ast_dial * | dial | ) |
Return state of dial.
dial | Dialing structure |
Definition at line 769 of file dial.c.
References ast_dial::state.
Referenced by dial_trunk(), and sla_handle_dial_state_event().
{ return dial->state; }
static void* async_dial | ( | void * | data | ) | [static] |
Dial async thread function.
Definition at line 684 of file dial.c.
References monitor_dial().
Referenced by ast_dial_run().
{ 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; }
static int begin_dial | ( | struct ast_dial * | dial, |
struct ast_channel * | chan | ||
) | [static] |
Helper function that does the beginning dialing per dial structure.
Definition at line 311 of file dial.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, begin_dial_channel(), ast_dial::channels, and ast_dial_channel::list.
Referenced by ast_dial_run().
{ struct ast_dial_channel *channel = NULL; int success = 0; /* Iterate through channel list, requesting and calling each one */ AST_LIST_LOCK(&dial->channels); AST_LIST_TRAVERSE(&dial->channels, channel, list) { success += begin_dial_channel(channel, chan); } AST_LIST_UNLOCK(&dial->channels); /* If number of failures matches the number of channels, then this truly failed */ return success; }
static int begin_dial_channel | ( | struct ast_dial_channel * | channel, |
struct ast_channel * | chan | ||
) | [static] |
Helper function that does the beginning dialing per-appended channel.
Definition at line 255 of file dial.c.
References ast_channel::accountcode, accountcode, ast_channel::adsicpe, ast_channel::appl, ast_call(), ast_channel_datastore_inherit(), ast_channel_inherit_variables(), ast_copy_string(), AST_FORMAT_AUDIO_MASK, ast_hangup(), AST_MAX_EXTENSION, ast_poll_channel_add(), ast_request(), ast_strdup, ast_string_field_set, ast_strlen_zero(), ast_verb, ast_dial_channel::cause, ast_channel::cdrflags, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_name, ast_callerid::cid_num, ast_callerid::cid_pres, ast_callerid::cid_rdnis, ast_callerid::cid_tns, ast_callerid::cid_ton, ast_channel::data, ast_dial_channel::device, ast_channel::language, language, musicclass, ast_channel::musicclass, ast_channel::nativeformats, ast_dial_channel::owner, S_REPLACE, ast_dial_channel::tech, ast_channel::transfercapability, and ast_channel::whentohangup.
Referenced by begin_dial(), and handle_call_forward().
{ 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)"; memset(&channel->owner->whentohangup, 0, sizeof(channel->owner->whentohangup)); /* Inherit everything from he who spawned this dial */ if (chan) { ast_channel_inherit_variables(chan, channel->owner); ast_channel_datastore_inherit(chan, channel->owner); /* 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 { if (chan) ast_poll_channel_add(chan, channel->owner); res = 1; ast_verb(3, "Called %s\n", numsubst); } return res; }
static struct ast_dial_channel* find_dial_channel | ( | struct ast_dial * | dial, |
int | num | ||
) | [static, read] |
Helper function for finding a channel in a dial structure based on number.
Definition at line 924 of file dial.c.
References AST_LIST_LAST, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_dial::channels, ast_dial_channel::list, and ast_dial_channel::num.
Referenced by ast_dial_option_disable(), ast_dial_option_enable(), and ast_dial_set_timeout().
{ 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! */ AST_LIST_LOCK(&dial->channels); AST_LIST_TRAVERSE(&dial->channels, channel, list) { if (channel->num == num) break; } AST_LIST_UNLOCK(&dial->channels); return channel; }
static struct ast_dial_channel* find_relative_dial_channel | ( | struct ast_dial * | dial, |
struct ast_channel * | owner | ||
) | [static, read] |
Helper function that finds the dialed channel based on owner.
Definition at line 367 of file dial.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_dial::channels, ast_dial_channel::list, and ast_dial_channel::owner.
Referenced by monitor_dial().
{ struct ast_dial_channel *channel = NULL; AST_LIST_LOCK(&dial->channels); AST_LIST_TRAVERSE(&dial->channels, channel, list) { if (channel->owner == owner) break; } AST_LIST_UNLOCK(&dial->channels); return channel; }
static int handle_call_forward | ( | struct ast_dial * | dial, |
struct ast_dial_channel * | channel, | ||
struct ast_channel * | chan | ||
) | [static] |
Helper function to handle channels that have been call forwarded.
Definition at line 328 of file dial.c.
References AST_DIAL_OPTION_DISABLE_CALL_FORWARDING, ast_free, ast_hangup(), AST_LIST_UNLOCK, ast_strdup, ast_strdupa, begin_dial_channel(), ast_channel::call_forward, ast_dial::channels, ast_dial_channel::device, FIND_RELATIVE_OPTION, ast_dial_channel::owner, and ast_dial_channel::tech.
Referenced by monitor_dial().
{ struct ast_channel *original = channel->owner; char *tmp = ast_strdupa(channel->owner->call_forward); char *tech = "Local", *device = tmp, *stuff; /* 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; } /* Figure out the new destination */ if ((stuff = strchr(tmp, '/'))) { *stuff++ = '\0'; tech = tmp; device = stuff; } /* Drop old destination information */ ast_free(channel->tech); ast_free(channel->device); /* Update the dial channel with the new destination information */ channel->tech = ast_strdup(tech); channel->device = ast_strdup(device); AST_LIST_UNLOCK(&dial->channels); /* Finally give it a go... send it out into the world */ begin_dial_channel(channel, chan); /* Drop the original channel */ ast_hangup(original); return 0; }
static void handle_frame | ( | struct ast_dial * | dial, |
struct ast_dial_channel * | channel, | ||
struct ast_frame * | fr, | ||
struct ast_channel * | chan | ||
) | [static] |
Helper function that handles control frames WITH owner.
Definition at line 390 of file dial.c.
References AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HOLD, AST_CONTROL_OFFHOOK, AST_CONTROL_PROCEEDING, AST_CONTROL_PROGRESS, AST_CONTROL_RINGING, AST_CONTROL_SRCUPDATE, AST_CONTROL_UNHOLD, AST_CONTROL_VIDUPDATE, AST_DIAL_OPTION_MUSIC, AST_DIAL_RESULT_ANSWERED, AST_DIAL_RESULT_PROCEEDING, AST_DIAL_RESULT_PROGRESS, AST_DIAL_RESULT_RINGING, AST_FRAME_CONTROL, ast_hangup(), ast_indicate(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_verb, ast_verbose(), ast_dial::channels, ast_frame::frametype, ast_dial_channel::list, ast_channel::name, option_verbose, ast_dial::options, ast_dial_channel::owner, set_state(), ast_frame::subclass, and VERBOSE_PREFIX_3.
Referenced by monitor_dial().
{ if (fr->frametype == AST_FRAME_CONTROL) { switch (fr->subclass) { case AST_CONTROL_ANSWER: ast_verb(3, "%s answered %s\n", channel->owner->name, chan->name); AST_LIST_LOCK(&dial->channels); AST_LIST_REMOVE(&dial->channels, channel, list); AST_LIST_INSERT_HEAD(&dial->channels, channel, list); AST_LIST_UNLOCK(&dial->channels); set_state(dial, AST_DIAL_RESULT_ANSWERED); break; case AST_CONTROL_BUSY: ast_verb(3, "%s is busy\n", channel->owner->name); ast_hangup(channel->owner); channel->owner = NULL; break; case AST_CONTROL_CONGESTION: ast_verb(3, "%s is circuit-busy\n", channel->owner->name); ast_hangup(channel->owner); channel->owner = NULL; break; case AST_CONTROL_RINGING: ast_verb(3, "%s is ringing\n", channel->owner->name); if (!dial->options[AST_DIAL_OPTION_MUSIC]) ast_indicate(chan, AST_CONTROL_RINGING); set_state(dial, AST_DIAL_RESULT_RINGING); break; case AST_CONTROL_PROGRESS: ast_verb(3, "%s is making progress, passing it to %s\n", channel->owner->name, chan->name); ast_indicate(chan, AST_CONTROL_PROGRESS); set_state(dial, AST_DIAL_RESULT_PROGRESS); break; case AST_CONTROL_VIDUPDATE: ast_verb(3, "%s requested a video update, passing it to %s\n", channel->owner->name, chan->name); ast_indicate(chan, AST_CONTROL_VIDUPDATE); break; 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); break; case AST_CONTROL_PROCEEDING: ast_verb(3, "%s is proceeding, passing it to %s\n", channel->owner->name, chan->name); ast_indicate(chan, AST_CONTROL_PROCEEDING); set_state(dial, AST_DIAL_RESULT_PROCEEDING); break; case AST_CONTROL_HOLD: ast_verb(3, "Call on %s placed on hold\n", chan->name); ast_indicate(chan, AST_CONTROL_HOLD); break; case AST_CONTROL_UNHOLD: ast_verb(3, "Call on %s left from hold\n", chan->name); 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; }
static void handle_frame_ownerless | ( | struct ast_dial * | dial, |
struct ast_dial_channel * | channel, | ||
struct ast_frame * | fr | ||
) | [static] |
Helper function that handles control frames WITHOUT owner.
Definition at line 461 of file dial.c.
References AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_PROCEEDING, AST_CONTROL_PROGRESS, AST_CONTROL_RINGING, AST_DIAL_RESULT_ANSWERED, AST_DIAL_RESULT_PROCEEDING, AST_DIAL_RESULT_PROGRESS, AST_DIAL_RESULT_RINGING, AST_FRAME_CONTROL, ast_hangup(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_verb, ast_dial::channels, ast_frame::frametype, ast_dial_channel::list, ast_channel::name, ast_dial_channel::owner, set_state(), and ast_frame::subclass.
Referenced by monitor_dial().
{ /* If we have no owner we can only update the state of the dial structure, so only look at control frames */ if (fr->frametype != AST_FRAME_CONTROL) return; switch (fr->subclass) { case AST_CONTROL_ANSWER: ast_verb(3, "%s answered\n", channel->owner->name); AST_LIST_LOCK(&dial->channels); AST_LIST_REMOVE(&dial->channels, channel, list); AST_LIST_INSERT_HEAD(&dial->channels, channel, list); AST_LIST_UNLOCK(&dial->channels); set_state(dial, AST_DIAL_RESULT_ANSWERED); break; case AST_CONTROL_BUSY: ast_verb(3, "%s is busy\n", channel->owner->name); ast_hangup(channel->owner); channel->owner = NULL; break; case AST_CONTROL_CONGESTION: ast_verb(3, "%s is circuit-busy\n", channel->owner->name); ast_hangup(channel->owner); channel->owner = NULL; break; case AST_CONTROL_RINGING: ast_verb(3, "%s is ringing\n", channel->owner->name); set_state(dial, AST_DIAL_RESULT_RINGING); break; case AST_CONTROL_PROGRESS: ast_verb(3, "%s is making progress\n", channel->owner->name); set_state(dial, AST_DIAL_RESULT_PROGRESS); break; case AST_CONTROL_PROCEEDING: ast_verb(3, "%s is proceeding\n", channel->owner->name); set_state(dial, AST_DIAL_RESULT_PROCEEDING); break; default: break; } return; }
static int handle_timeout_trip | ( | struct ast_dial * | dial, |
struct timeval | start | ||
) | [static] |
Helper function to handle when a timeout occurs on dialing attempt.
Definition at line 506 of file dial.c.
References AST_DIAL_RESULT_TIMEOUT, ast_hangup(), AST_LIST_TRAVERSE, ast_tvdiff_ms(), ast_tvnow(), ast_dial::channels, ast_dial_channel::list, ast_dial_channel::owner, set_state(), ast_dial::state, ast_dial_channel::timeout, and ast_dial::timeout.
Referenced by monitor_dial().
{ 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; }
static enum ast_dial_result monitor_dial | ( | struct ast_dial * | dial, |
struct ast_channel * | chan | ||
) | [static] |
Helper function that basically keeps tabs on dialing attempts.
Definition at line 535 of file dial.c.
References ast_dial::actual_timeout, answer_exec_run(), answer_exec_struct::app, answer_exec_struct::args, AST_CONTROL_RINGING, AST_DIAL_OPTION_ANSWER_EXEC, AST_DIAL_OPTION_MUSIC, AST_DIAL_OPTION_RINGING, AST_DIAL_RESULT_ANSWERED, AST_DIAL_RESULT_HANGUP, AST_DIAL_RESULT_RINGING, AST_DIAL_RESULT_TIMEOUT, AST_DIAL_RESULT_TRYING, AST_DIAL_RESULT_UNANSWERED, ast_frfree, ast_hangup(), ast_indicate(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, AST_MAX_WATCHERS, ast_moh_start(), ast_moh_stop(), ast_poll_channel_del(), AST_PTHREADT_STOP, ast_read(), ast_strdupa, ast_string_field_set, ast_strlen_zero(), ast_tvnow(), ast_waitfor_n(), ast_channel::call_forward, chan, ast_dial::channels, find_relative_dial_channel(), FIND_RELATIVE_OPTION, handle_call_forward(), handle_frame(), handle_frame_ownerless(), handle_timeout_trip(), IS_CALLER, ast_dial_channel::is_running_app, musicclass, ast_channel::musicclass, ast_dial::options, ast_dial_channel::owner, set_state(), ast_dial::state, and ast_dial::thread.
Referenced by ast_dial_run(), and async_dial().
{ int timeout = -1; struct ast_channel *cs[AST_MAX_WATCHERS], *who = NULL; struct ast_dial_channel *channel = NULL; struct answer_exec_struct *answer_exec = NULL; struct timeval start; set_state(dial, AST_DIAL_RESULT_TRYING); /* If the "always indicate ringing" option is set, change state to ringing and indicate to the owner if present */ if (dial->options[AST_DIAL_OPTION_RINGING]) { set_state(dial, AST_DIAL_RESULT_RINGING); if (chan) ast_indicate(chan, AST_CONTROL_RINGING); } 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); } /* 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; /* Go into an infinite loop while we are trying */ 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)) { int pos = 0, count = 0; 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 */ AST_LIST_LOCK(&dial->channels); AST_LIST_TRAVERSE(&dial->channels, channel, list) { if (channel->owner) { cs[pos++] = channel->owner; count++; } } AST_LIST_UNLOCK(&dial->channels); /* If we have no outbound channels in progress, switch state to unanswered and stop */ if (!count) { set_state(dial, AST_DIAL_RESULT_UNANSWERED); 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; /* 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); continue; } /* Find relative dial channel */ if (!chan || !IS_CALLER(chan, who)) channel = find_relative_dial_channel(dial, who); /* See if this channel has been forwarded elsewhere */ if (!ast_strlen_zero(who->call_forward)) { handle_call_forward(dial, channel, chan); continue; } /* Attempt to read in a frame */ if (!(fr = ast_read(who))) { /* If this is the caller then we switch state to hangup and stop */ if (chan && IS_CALLER(chan, who)) { set_state(dial, AST_DIAL_RESULT_HANGUP); break; } if (chan) ast_poll_channel_del(chan, channel->owner); 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 */ if (dial->state == AST_DIAL_RESULT_ANSWERED) { /* Hangup everything except that which answered */ AST_LIST_LOCK(&dial->channels); AST_LIST_TRAVERSE(&dial->channels, channel, list) { if (!channel->owner || channel->owner == who) continue; if (chan) ast_poll_channel_del(chan, channel->owner); ast_hangup(channel->owner); channel->owner = NULL; } AST_LIST_UNLOCK(&dial->channels); /* If ANSWER_EXEC is enabled as an option, execute application on answered channel */ 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; } if (chan && dial->options[AST_DIAL_OPTION_MUSIC] && !ast_strlen_zero(dial->options[AST_DIAL_OPTION_MUSIC])) { ast_moh_stop(chan); } } else if (dial->state == AST_DIAL_RESULT_HANGUP) { /* Hangup everything */ AST_LIST_LOCK(&dial->channels); AST_LIST_TRAVERSE(&dial->channels, channel, list) { if (!channel->owner) continue; if (chan) ast_poll_channel_del(chan, channel->owner); ast_hangup(channel->owner); channel->owner = NULL; } AST_LIST_UNLOCK(&dial->channels); } return dial->state; }
static int music_disable | ( | void * | data | ) | [static] |
static void* music_enable | ( | void * | data | ) | [static] |
static void set_state | ( | struct ast_dial * | dial, |
enum ast_dial_result | state | ||
) | [static] |
Definition at line 381 of file dial.c.
References ast_dial::state, and ast_dial::state_callback.
Referenced by handle_frame(), handle_frame_ownerless(), handle_timeout_trip(), and monitor_dial().
{ dial->state = state; if (dial->state_callback) dial->state_callback(dial); }
struct ast_option_types option_types[] [static] |