#include "asterisk.h"
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/options.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/say.h"
#include "asterisk/config.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
#include "asterisk/callerid.h"
#include "asterisk/utils.h"
#include "asterisk/app.h"
#include "asterisk/causes.h"
#include "asterisk/rtp.h"
#include "asterisk/cdr.h"
#include "asterisk/manager.h"
#include "asterisk/privacy.h"
#include "asterisk/stringfields.h"
#include "asterisk/global_datastores.h"
#include "asterisk/transcap.h"
Go to the source code of this file.
Data Structures | |
struct | dial_localuser |
Defines | |
#define | AST_MAX_WATCHERS 256 |
#define | CAN_EARLY_BRIDGE(flags) |
#define | DIAL_NOFORWARDHTML (1 << 31) |
#define | DIAL_STILLGOING (1 << 30) |
#define | HANDLE_CAUSE(cause, chan) |
Enumerations | |
enum | { OPT_ANNOUNCE = (1 << 0), OPT_RESETCDR = (1 << 1), OPT_DTMF_EXIT = (1 << 2), OPT_SENDDTMF = (1 << 3), OPT_FORCECLID = (1 << 4), OPT_GO_ON = (1 << 5), OPT_CALLEE_HANGUP = (1 << 6), OPT_CALLER_HANGUP = (1 << 7), OPT_PRIORITY_JUMP = (1 << 8), OPT_DURATION_LIMIT = (1 << 9), OPT_MUSICBACK = (1 << 10), OPT_CALLEE_MACRO = (1 << 11), OPT_SCREEN_NOINTRO = (1 << 12), OPT_SCREEN_NOCLID = (1 << 13), OPT_ORIGINAL_CLID = (1 << 14), OPT_SCREENING = (1 << 15), OPT_PRIVACY = (1 << 16), OPT_RINGBACK = (1 << 17), OPT_DURATION_STOP = (1 << 18), OPT_CALLEE_TRANSFER = (1 << 19), OPT_CALLER_TRANSFER = (1 << 20), OPT_CALLEE_MONITOR = (1 << 21), OPT_CALLER_MONITOR = (1 << 22), OPT_GOTO = (1 << 23), OPT_OPERMODE = (1 << 24), OPT_CALLEE_PARK = (1 << 25), OPT_CALLER_PARK = (1 << 26), OPT_IGNORE_FORWARDING = (1 << 27), OPT_NOINBAND = (1 << 28), OPT_CALLBACK_INIT = (1 << 29) } |
enum | { OPT_ARG_ANNOUNCE = 0, OPT_ARG_SENDDTMF, OPT_ARG_GOTO, OPT_ARG_DURATION_LIMIT, OPT_ARG_MUSICBACK, OPT_ARG_CALLEE_MACRO, OPT_ARG_PRIVACY, OPT_ARG_DURATION_STOP, OPT_ARG_OPERMODE, OPT_ARG_ARRAY_SIZE } |
Functions | |
AST_APP_OPTIONS (dial_exec_options,{AST_APP_OPTION_ARG('A', OPT_ANNOUNCE, OPT_ARG_ANNOUNCE), AST_APP_OPTION('C', OPT_RESETCDR), AST_APP_OPTION('d', OPT_DTMF_EXIT), AST_APP_OPTION_ARG('D', OPT_SENDDTMF, OPT_ARG_SENDDTMF), AST_APP_OPTION('f', OPT_FORCECLID), AST_APP_OPTION('g', OPT_GO_ON), AST_APP_OPTION_ARG('G', OPT_GOTO, OPT_ARG_GOTO), AST_APP_OPTION('h', OPT_CALLEE_HANGUP), AST_APP_OPTION('H', OPT_CALLER_HANGUP), AST_APP_OPTION('i', OPT_IGNORE_FORWARDING), AST_APP_OPTION('j', OPT_PRIORITY_JUMP), AST_APP_OPTION('k', OPT_CALLEE_PARK), AST_APP_OPTION('K', OPT_CALLER_PARK), AST_APP_OPTION_ARG('L', OPT_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT), AST_APP_OPTION_ARG('m', OPT_MUSICBACK, OPT_ARG_MUSICBACK), AST_APP_OPTION_ARG('M', OPT_CALLEE_MACRO, OPT_ARG_CALLEE_MACRO), AST_APP_OPTION('n', OPT_SCREEN_NOINTRO), AST_APP_OPTION('N', OPT_SCREEN_NOCLID), AST_APP_OPTION('o', OPT_ORIGINAL_CLID), AST_APP_OPTION_ARG('O', OPT_OPERMODE, OPT_ARG_OPERMODE), AST_APP_OPTION('p', OPT_SCREENING), AST_APP_OPTION_ARG('P', OPT_PRIVACY, OPT_ARG_PRIVACY), AST_APP_OPTION('r', OPT_RINGBACK), AST_APP_OPTION('R', OPT_NOINBAND), AST_APP_OPTION('c', OPT_CALLBACK_INIT), AST_APP_OPTION_ARG('S', OPT_DURATION_STOP, OPT_ARG_DURATION_STOP), AST_APP_OPTION('t', OPT_CALLEE_TRANSFER), AST_APP_OPTION('T', OPT_CALLER_TRANSFER), AST_APP_OPTION('w', OPT_CALLEE_MONITOR), AST_APP_OPTION('W', OPT_CALLER_MONITOR),}) | |
AST_MODULE_INFO_STANDARD (ASTERISK_GPL_KEY,"Dialing Application") | |
static int | dial_exec (struct ast_channel *chan, void *data) |
static const char * | get_cid_name (char *name, int namelen, struct ast_channel *chan) |
static void | hanguptree (struct dial_localuser *outgoing, struct ast_channel *exception) |
static int | load_module (void) |
static int | onedigit_goto (struct ast_channel *chan, const char *context, char exten, int pri) |
static void | replace_macro_delimiter (char *s) |
static int | retrydial_exec (struct ast_channel *chan, void *data) |
static void | senddialevent (struct ast_channel *src, struct ast_channel *dst) |
static int | unload_module (void) |
static int | valid_priv_reply (struct ast_flags *opts, int res) |
static struct ast_channel * | wait_for_answer (struct ast_channel *in, struct dial_localuser *outgoing, int *to, struct ast_flags *peerflags, int *sentringing, char *status, size_t statussize, int busystart, int nochanstart, int congestionstart, int priority_jump, int *result) |
Variables | |
static char * | app = "Dial" |
static char * | descrip |
enum { ... } | dial_exec_option_args |
enum { ... } | dial_exec_option_flags |
static char * | rapp = "RetryDial" |
static char * | rdescrip |
static char * | rsynopsis = "Place a call, retrying on failure allowing optional exit extension." |
static char * | synopsis = "Place a call and connect to the current channel" |
Definition in file app_dial.c.
#define AST_MAX_WATCHERS 256 |
Definition at line 338 of file app_dial.c.
#define CAN_EARLY_BRIDGE | ( | flags | ) |
Value:
(!ast_test_flag(flags, OPT_CALLEE_HANGUP | \ OPT_CALLER_HANGUP | OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER | \ OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR | OPT_CALLEE_PARK | OPT_CALLER_PARK))
Definition at line 309 of file app_dial.c.
Referenced by wait_for_answer().
#define DIAL_NOFORWARDHTML (1 << 31) |
#define DIAL_STILLGOING (1 << 30) |
#define HANDLE_CAUSE | ( | cause, | |||
chan | ) |
anonymous enum |
Definition at line 226 of file app_dial.c.
00226 { 00227 OPT_ANNOUNCE = (1 << 0), 00228 OPT_RESETCDR = (1 << 1), 00229 OPT_DTMF_EXIT = (1 << 2), 00230 OPT_SENDDTMF = (1 << 3), 00231 OPT_FORCECLID = (1 << 4), 00232 OPT_GO_ON = (1 << 5), 00233 OPT_CALLEE_HANGUP = (1 << 6), 00234 OPT_CALLER_HANGUP = (1 << 7), 00235 OPT_PRIORITY_JUMP = (1 << 8), 00236 OPT_DURATION_LIMIT = (1 << 9), 00237 OPT_MUSICBACK = (1 << 10), 00238 OPT_CALLEE_MACRO = (1 << 11), 00239 OPT_SCREEN_NOINTRO = (1 << 12), 00240 OPT_SCREEN_NOCLID = (1 << 13), 00241 OPT_ORIGINAL_CLID = (1 << 14), 00242 OPT_SCREENING = (1 << 15), 00243 OPT_PRIVACY = (1 << 16), 00244 OPT_RINGBACK = (1 << 17), 00245 OPT_DURATION_STOP = (1 << 18), 00246 OPT_CALLEE_TRANSFER = (1 << 19), 00247 OPT_CALLER_TRANSFER = (1 << 20), 00248 OPT_CALLEE_MONITOR = (1 << 21), 00249 OPT_CALLER_MONITOR = (1 << 22), 00250 OPT_GOTO = (1 << 23), 00251 OPT_OPERMODE = (1 << 24), 00252 OPT_CALLEE_PARK = (1 << 25), 00253 OPT_CALLER_PARK = (1 << 26), 00254 OPT_IGNORE_FORWARDING = (1 << 27), 00255 OPT_NOINBAND = (1 << 28), 00256 OPT_CALLBACK_INIT = (1 << 29), 00257 } dial_exec_option_flags;
anonymous enum |
OPT_ARG_ANNOUNCE | |
OPT_ARG_SENDDTMF | |
OPT_ARG_GOTO | |
OPT_ARG_DURATION_LIMIT | |
OPT_ARG_MUSICBACK | |
OPT_ARG_CALLEE_MACRO | |
OPT_ARG_PRIVACY | |
OPT_ARG_DURATION_STOP | |
OPT_ARG_OPERMODE | |
OPT_ARG_ARRAY_SIZE |
Definition at line 262 of file app_dial.c.
00262 { 00263 OPT_ARG_ANNOUNCE = 0, 00264 OPT_ARG_SENDDTMF, 00265 OPT_ARG_GOTO, 00266 OPT_ARG_DURATION_LIMIT, 00267 OPT_ARG_MUSICBACK, 00268 OPT_ARG_CALLEE_MACRO, 00269 OPT_ARG_PRIVACY, 00270 OPT_ARG_DURATION_STOP, 00271 OPT_ARG_OPERMODE, 00272 /* note: this entry _MUST_ be the last one in the enum */ 00273 OPT_ARG_ARRAY_SIZE, 00274 } dial_exec_option_args;
AST_APP_OPTIONS | ( | dial_exec_options | ) |
AST_MODULE_INFO_STANDARD | ( | ASTERISK_GPL_KEY | , | |
"Dialing Application" | ||||
) |
static int dial_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 1772 of file app_dial.c.
Referenced by load_module().
01773 { 01774 struct ast_flags peerflags; 01775 01776 memset(&peerflags, 0, sizeof(peerflags)); 01777 01778 return dial_exec_full(chan, data, &peerflags, NULL); 01779 }
static const char* get_cid_name | ( | char * | name, | |
int | namelen, | |||
struct ast_channel * | chan | |||
) | [static] |
Definition at line 385 of file app_dial.c.
References ast_get_hint(), ast_channel::context, context, ast_channel::exten, exten, ast_channel::macrocontext, ast_channel::macroexten, and S_OR.
Referenced by wait_for_answer().
00386 { 00387 const char *context = S_OR(chan->macrocontext, chan->context); 00388 const char *exten = S_OR(chan->macroexten, chan->exten); 00389 00390 return ast_get_hint(NULL, 0, name, namelen, chan, context, exten) ? name : ""; 00391 }
static void hanguptree | ( | struct dial_localuser * | outgoing, | |
struct ast_channel * | exception | |||
) | [static] |
Definition at line 324 of file app_dial.c.
References ast_hangup(), dial_localuser::chan, free, and dial_localuser::next.
00325 { 00326 /* Hang up a tree of stuff */ 00327 struct dial_localuser *oo; 00328 while (outgoing) { 00329 /* Hangup any existing lines we have open */ 00330 if (outgoing->chan && (outgoing->chan != exception)) 00331 ast_hangup(outgoing->chan); 00332 oo = outgoing; 00333 outgoing=outgoing->next; 00334 free(oo); 00335 } 00336 }
static int load_module | ( | void | ) | [static] |
Definition at line 1909 of file app_dial.c.
References ast_register_application(), dial_exec(), and retrydial_exec().
01910 { 01911 int res; 01912 01913 res = ast_register_application(app, dial_exec, synopsis, descrip); 01914 res |= ast_register_application(rapp, retrydial_exec, rsynopsis, rdescrip); 01915 01916 return res; 01917 }
static int onedigit_goto | ( | struct ast_channel * | chan, | |
const char * | context, | |||
char | exten, | |||
int | pri | |||
) | [static] |
Definition at line 366 of file app_dial.c.
References ast_goto_if_exists(), ast_strlen_zero(), ast_channel::context, and ast_channel::macrocontext.
Referenced by retrydial_exec(), and wait_for_answer().
00367 { 00368 char rexten[2] = { exten, '\0' }; 00369 00370 if (context) { 00371 if (!ast_goto_if_exists(chan, context, rexten, pri)) 00372 return 1; 00373 } else { 00374 if (!ast_goto_if_exists(chan, chan->context, rexten, pri)) 00375 return 1; 00376 else if (!ast_strlen_zero(chan->macrocontext)) { 00377 if (!ast_goto_if_exists(chan, chan->macrocontext, rexten, pri)) 00378 return 1; 00379 } 00380 } 00381 return 0; 00382 }
static void replace_macro_delimiter | ( | char * | s | ) | [static] |
static int retrydial_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 1781 of file app_dial.c.
References AST_DIGIT_ANY, ast_fileexists(), AST_FLAG_MOH, ast_log(), ast_module_user_add, ast_module_user_remove, ast_moh_start(), ast_moh_stop(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_waitfordigit(), ast_waitstream(), context, ast_channel::data, LOG_ERROR, LOG_WARNING, onedigit_goto(), OPT_DTMF_EXIT, and pbx_builtin_getvar_helper().
Referenced by load_module().
01782 { 01783 char *announce = NULL, *dialdata = NULL; 01784 const char *context = NULL; 01785 int sleep = 0, loops = 0, res = -1; 01786 struct ast_module_user *u; 01787 struct ast_flags peerflags; 01788 01789 if (ast_strlen_zero(data)) { 01790 ast_log(LOG_WARNING, "RetryDial requires an argument!\n"); 01791 return -1; 01792 } 01793 01794 u = ast_module_user_add(chan); 01795 01796 announce = ast_strdupa(data); 01797 01798 memset(&peerflags, 0, sizeof(peerflags)); 01799 01800 if ((dialdata = strchr(announce, '|'))) { 01801 *dialdata++ = '\0'; 01802 if (sscanf(dialdata, "%d", &sleep) == 1) { 01803 sleep *= 1000; 01804 } else { 01805 ast_log(LOG_ERROR, "%s requires the numerical argument <sleep>\n",rapp); 01806 goto done; 01807 } 01808 if ((dialdata = strchr(dialdata, '|'))) { 01809 *dialdata++ = '\0'; 01810 if (sscanf(dialdata, "%d", &loops) != 1) { 01811 ast_log(LOG_ERROR, "%s requires the numerical argument <loops>\n",rapp); 01812 goto done; 01813 } 01814 } 01815 } 01816 01817 if ((dialdata = strchr(dialdata, '|'))) { 01818 *dialdata++ = '\0'; 01819 } else { 01820 ast_log(LOG_ERROR, "%s requires more arguments\n",rapp); 01821 goto done; 01822 } 01823 01824 if (sleep < 1000) 01825 sleep = 10000; 01826 01827 if (!loops) 01828 loops = -1; /* run forever */ 01829 01830 context = pbx_builtin_getvar_helper(chan, "EXITCONTEXT"); 01831 01832 res = 0; 01833 while (loops) { 01834 int continue_exec; 01835 01836 chan->data = "Retrying"; 01837 if (ast_test_flag(chan, AST_FLAG_MOH)) 01838 ast_moh_stop(chan); 01839 01840 res = dial_exec_full(chan, dialdata, &peerflags, &continue_exec); 01841 if (continue_exec) 01842 break; 01843 01844 if (res == 0) { 01845 if (ast_test_flag(&peerflags, OPT_DTMF_EXIT)) { 01846 if (!ast_strlen_zero(announce)) { 01847 if (ast_fileexists(announce, NULL, chan->language) > 0) { 01848 if(!(res = ast_streamfile(chan, announce, chan->language))) 01849 ast_waitstream(chan, AST_DIGIT_ANY); 01850 } else 01851 ast_log(LOG_WARNING, "Announce file \"%s\" specified in Retrydial does not exist\n", announce); 01852 } 01853 if (!res && sleep) { 01854 if (!ast_test_flag(chan, AST_FLAG_MOH)) 01855 ast_moh_start(chan, NULL, NULL); 01856 res = ast_waitfordigit(chan, sleep); 01857 } 01858 } else { 01859 if (!ast_strlen_zero(announce)) { 01860 if (ast_fileexists(announce, NULL, chan->language) > 0) { 01861 if (!(res = ast_streamfile(chan, announce, chan->language))) 01862 res = ast_waitstream(chan, ""); 01863 } else 01864 ast_log(LOG_WARNING, "Announce file \"%s\" specified in Retrydial does not exist\n", announce); 01865 } 01866 if (sleep) { 01867 if (!ast_test_flag(chan, AST_FLAG_MOH)) 01868 ast_moh_start(chan, NULL, NULL); 01869 if (!res) 01870 res = ast_waitfordigit(chan, sleep); 01871 } 01872 } 01873 } 01874 01875 if (res < 0) 01876 break; 01877 else if (res > 0) { /* Trying to send the call elsewhere (1 digit ext) */ 01878 if (onedigit_goto(chan, context, (char) res, 1)) { 01879 res = 0; 01880 break; 01881 } 01882 } 01883 loops--; 01884 } 01885 if (loops == 0) 01886 res = 0; 01887 else if (res == 1) 01888 res = 0; 01889 01890 if (ast_test_flag(chan, AST_FLAG_MOH)) 01891 ast_moh_stop(chan); 01892 done: 01893 ast_module_user_remove(u); 01894 return res; 01895 }
static void senddialevent | ( | struct ast_channel * | src, | |
struct ast_channel * | dst | |||
) | [static] |
Definition at line 393 of file app_dial.c.
References ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, EVENT_FLAG_CALL, manager_event(), and S_OR.
Referenced by wait_for_answer().
00394 { 00395 /* XXX do we need also CallerIDnum ? */ 00396 manager_event(EVENT_FLAG_CALL, "Dial", 00397 "Source: %s\r\n" 00398 "Destination: %s\r\n" 00399 "CallerID: %s\r\n" 00400 "CallerIDName: %s\r\n" 00401 "SrcUniqueID: %s\r\n" 00402 "DestUniqueID: %s\r\n", 00403 src->name, dst->name, S_OR(src->cid.cid_num, "<unknown>"), 00404 S_OR(src->cid.cid_name, "<unknown>"), src->uniqueid, 00405 dst->uniqueid); 00406 }
static int unload_module | ( | void | ) | [static] |
Definition at line 1897 of file app_dial.c.
References ast_module_user_hangup_all, and ast_unregister_application().
01898 { 01899 int res; 01900 01901 res = ast_unregister_application(app); 01902 res |= ast_unregister_application(rapp); 01903 01904 ast_module_user_hangup_all(); 01905 01906 return res; 01907 }
static int valid_priv_reply | ( | struct ast_flags * | opts, | |
int | res | |||
) | [static] |
Definition at line 808 of file app_dial.c.
References ast_test_flag, OPT_PRIVACY, and OPT_SCREENING.
00809 { 00810 if (res < '1') 00811 return 0; 00812 if (ast_test_flag(opts, OPT_PRIVACY) && res <= '5') 00813 return 1; 00814 if (ast_test_flag(opts, OPT_SCREENING) && res <= '4') 00815 return 1; 00816 return 0; 00817 }
static struct ast_channel* wait_for_answer | ( | struct ast_channel * | in, | |
struct dial_localuser * | outgoing, | |||
int * | to, | |||
struct ast_flags * | peerflags, | |||
int * | sentringing, | |||
char * | status, | |||
size_t | statussize, | |||
int | busystart, | |||
int | nochanstart, | |||
int | congestionstart, | |||
int | priority_jump, | |||
int * | result | |||
) | [static, read] |
Definition at line 408 of file app_dial.c.
References ast_channel::_state, accountcode, ast_call(), AST_CAUSE_BUSY, AST_CAUSE_CONGESTION, AST_CAUSE_NORMAL_CLEARING, AST_CDR_FLAG_POST_DISABLED, ast_cdr_log_unanswered(), ast_cdr_noanswer(), ast_channel_datastore_inherit(), ast_channel_inherit_variables(), ast_channel_make_compatible(), ast_channel_sendhtml(), ast_check_hangup(), ast_clear_flag, AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OFFHOOK, AST_CONTROL_PROCEEDING, AST_CONTROL_PROGRESS, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, AST_CONTROL_VIDUPDATE, ast_copy_flags, ast_deactivate_generator(), AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_HTML, AST_FRAME_IMAGE, AST_FRAME_TEXT, AST_FRAME_VOICE, ast_frfree, ast_goto_if_exists(), ast_hangup(), ast_indicate(), ast_indicate_data(), ast_log(), AST_MAX_EXTENSION, AST_MAX_WATCHERS, ast_opt_priority_jumping, ast_read(), ast_request(), ast_rtp_early_bridge(), ast_rtp_make_compatible(), ast_set_callerid(), ast_set_flag, AST_STATE_UP, ast_strdup, ast_string_field_set, ast_strlen_zero(), ast_test_flag, ast_verbose(), ast_waitfor_n(), ast_write(), CAN_EARLY_BRIDGE, ast_channel::cdr, ast_channel::cdrflags, dial_localuser::chan, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_name, ast_callerid::cid_num, ast_callerid::cid_rdnis, context, ast_channel::context, ast_frame::data, ast_frame::datalen, DIAL_NOFORWARDHTML, DIAL_STILLGOING, ast_channel::dialcontext, ast_channel::exten, f, ast_frame::frametype, free, get_cid_name(), HANDLE_CAUSE, ast_channel::hangupcause, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, ast_channel::macroexten, ast_channel::nativeformats, dial_localuser::next, onedigit_goto(), OPT_CALLBACK_INIT, OPT_CALLEE_HANGUP, OPT_CALLEE_MONITOR, OPT_CALLEE_PARK, OPT_CALLEE_TRANSFER, OPT_CALLER_HANGUP, OPT_CALLER_MONITOR, OPT_CALLER_PARK, OPT_CALLER_TRANSFER, OPT_DTMF_EXIT, OPT_FORCECLID, OPT_IGNORE_FORWARDING, OPT_MUSICBACK, OPT_NOINBAND, OPT_ORIGINAL_CLID, OPT_RINGBACK, option_debug, option_verbose, pbx_builtin_getvar_helper(), ast_channel::priority, S_OR, senddialevent(), ast_frame::subclass, ast_channel::tech, VERBOSE_PREFIX_2, and VERBOSE_PREFIX_3.
Referenced by try_calling().
00409 { 00410 int numbusy = busystart; 00411 int numcongestion = congestionstart; 00412 int numnochan = nochanstart; 00413 int prestart = busystart + congestionstart + nochanstart; 00414 int orig = *to; 00415 struct ast_channel *peer = NULL; 00416 /* single is set if only one destination is enabled */ 00417 int single = (outgoing && !outgoing->next && !ast_test_flag(outgoing, OPT_MUSICBACK | OPT_RINGBACK | OPT_NOINBAND)); 00418 00419 if (single) { 00420 /* Turn off hold music, etc */ 00421 ast_deactivate_generator(in); 00422 /* If we are calling a single channel, make them compatible for in-band tone purpose */ 00423 ast_channel_make_compatible(outgoing->chan, in); 00424 } 00425 00426 00427 while (*to && !peer) { 00428 struct dial_localuser *o; 00429 int pos = 0; /* how many channels do we handle */ 00430 int numlines = prestart; 00431 struct ast_channel *winner; 00432 struct ast_channel *watchers[AST_MAX_WATCHERS]; 00433 00434 watchers[pos++] = in; 00435 for (o = outgoing; o; o = o->next) { 00436 /* Keep track of important channels */ 00437 if (ast_test_flag(o, DIAL_STILLGOING) && o->chan) 00438 watchers[pos++] = o->chan; 00439 numlines++; 00440 } 00441 if (pos == 1) { /* only the input channel is available */ 00442 if (numlines == (numbusy + numcongestion + numnochan)) { 00443 if (option_verbose > 2) 00444 ast_verbose( VERBOSE_PREFIX_2 "Everyone is busy/congested at this time (%d:%d/%d/%d)\n", numlines, numbusy, numcongestion, numnochan); 00445 if (numbusy) 00446 strcpy(status, "BUSY"); 00447 else if (numcongestion) 00448 strcpy(status, "CONGESTION"); 00449 else if (numnochan) 00450 strcpy(status, "CHANUNAVAIL"); 00451 if (ast_opt_priority_jumping || priority_jump) 00452 ast_goto_if_exists(in, in->context, in->exten, in->priority + 101); 00453 } else { 00454 if (option_verbose > 2) 00455 ast_verbose(VERBOSE_PREFIX_3 "No one is available to answer at this time (%d:%d/%d/%d)\n", numlines, numbusy, numcongestion, numnochan); 00456 } 00457 *to = 0; 00458 return NULL; 00459 } 00460 winner = ast_waitfor_n(watchers, pos, to); 00461 for (o = outgoing; o; o = o->next) { 00462 struct ast_frame *f; 00463 struct ast_channel *c = o->chan; 00464 00465 if (c == NULL) 00466 continue; 00467 if (ast_test_flag(o, DIAL_STILLGOING) && c->_state == AST_STATE_UP) { 00468 if (!peer) { 00469 if (option_verbose > 2) 00470 ast_verbose(VERBOSE_PREFIX_3 "%s answered %s\n", c->name, in->name); 00471 peer = c; 00472 ast_copy_flags(peerflags, o, 00473 OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER | 00474 OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP | 00475 OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR | 00476 OPT_CALLEE_PARK | OPT_CALLER_PARK | 00477 DIAL_NOFORWARDHTML); 00478 ast_copy_string(c->dialcontext, "", sizeof(c->dialcontext)); 00479 ast_copy_string(c->exten, "", sizeof(c->exten)); 00480 } 00481 continue; 00482 } 00483 if (c != winner) 00484 continue; 00485 if (!ast_strlen_zero(c->call_forward)) { 00486 char tmpchan[256]; 00487 char *stuff; 00488 char *tech; 00489 int cause; 00490 00491 ast_copy_string(tmpchan, c->call_forward, sizeof(tmpchan)); 00492 if ((stuff = strchr(tmpchan, '/'))) { 00493 *stuff++ = '\0'; 00494 tech = tmpchan; 00495 } else { 00496 const char *forward_context = pbx_builtin_getvar_helper(c, "FORWARD_CONTEXT"); 00497 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", c->call_forward, forward_context ? forward_context : c->context); 00498 stuff = tmpchan; 00499 tech = "Local"; 00500 } 00501 /* Before processing channel, go ahead and check for forwarding */ 00502 if (option_verbose > 2) 00503 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, c->name); 00504 /* If we have been told to ignore forwards, just set this channel to null and continue processing extensions normally */ 00505 if (ast_test_flag(peerflags, OPT_IGNORE_FORWARDING)) { 00506 if (option_verbose > 2) 00507 ast_verbose(VERBOSE_PREFIX_3 "Forwarding %s to '%s/%s' prevented.\n", in->name, tech, stuff); 00508 c = o->chan = NULL; 00509 cause = AST_CAUSE_BUSY; 00510 } else { 00511 /* Setup parameters */ 00512 if ((c = o->chan = ast_request(tech, in->nativeformats, stuff, &cause))) { 00513 if (single) 00514 ast_channel_make_compatible(o->chan, in); 00515 ast_channel_inherit_variables(in, o->chan); 00516 ast_channel_datastore_inherit(in, o->chan); 00517 } else 00518 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause); 00519 } 00520 if (!c) { 00521 ast_clear_flag(o, DIAL_STILLGOING); 00522 HANDLE_CAUSE(cause, in); 00523 } else { 00524 ast_rtp_make_compatible(c, in, single); 00525 if (c->cid.cid_num) 00526 free(c->cid.cid_num); 00527 c->cid.cid_num = NULL; 00528 if (c->cid.cid_name) 00529 free(c->cid.cid_name); 00530 c->cid.cid_name = NULL; 00531 00532 if (ast_test_flag(o, OPT_FORCECLID)) { 00533 c->cid.cid_num = ast_strdup(S_OR(in->macroexten, in->exten)); 00534 ast_string_field_set(c, accountcode, winner->accountcode); 00535 c->cdrflags = winner->cdrflags; 00536 } else { 00537 c->cid.cid_num = ast_strdup(in->cid.cid_num); 00538 c->cid.cid_name = ast_strdup(in->cid.cid_name); 00539 ast_string_field_set(c, accountcode, in->accountcode); 00540 c->cdrflags = in->cdrflags; 00541 } 00542 00543 if (in->cid.cid_ani) { 00544 if (c->cid.cid_ani) 00545 free(c->cid.cid_ani); 00546 c->cid.cid_ani = ast_strdup(in->cid.cid_ani); 00547 } 00548 if (c->cid.cid_rdnis) 00549 free(c->cid.cid_rdnis); 00550 c->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten)); 00551 if (ast_call(c, tmpchan, 0)) { 00552 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan); 00553 ast_clear_flag(o, DIAL_STILLGOING); 00554 ast_hangup(c); 00555 c = o->chan = NULL; 00556 numnochan++; 00557 } else { 00558 senddialevent(in, c); 00559 /* After calling, set callerid to extension */ 00560 if (!ast_test_flag(peerflags, OPT_ORIGINAL_CLID)) { 00561 char cidname[AST_MAX_EXTENSION] = ""; 00562 ast_set_callerid(c, S_OR(in->macroexten, in->exten), get_cid_name(cidname, sizeof(cidname), in), NULL); 00563 } 00564 } 00565 } 00566 /* Hangup the original channel now, in case we needed it */ 00567 ast_hangup(winner); 00568 continue; 00569 } 00570 f = ast_read(winner); 00571 if (!f) { 00572 in->hangupcause = c->hangupcause; 00573 ast_hangup(c); 00574 c = o->chan = NULL; 00575 ast_clear_flag(o, DIAL_STILLGOING); 00576 HANDLE_CAUSE(in->hangupcause, in); 00577 continue; 00578 } 00579 if (f->frametype == AST_FRAME_CONTROL) { 00580 switch(f->subclass) { 00581 case AST_CONTROL_ANSWER: 00582 /* This is our guy if someone answered. */ 00583 if (!peer) { 00584 if (option_verbose > 2) 00585 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", c->name, in->name); 00586 peer = c; 00587 ast_copy_flags(peerflags, o, 00588 OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER | 00589 OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP | 00590 OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR | 00591 OPT_CALLEE_PARK | OPT_CALLER_PARK | 00592 DIAL_NOFORWARDHTML); 00593 ast_copy_string(c->dialcontext, "", sizeof(c->dialcontext)); 00594 ast_copy_string(c->exten, "", sizeof(c->exten)); 00595 /* Setup RTP early bridge if appropriate */ 00596 if (CAN_EARLY_BRIDGE(peerflags)) 00597 ast_rtp_early_bridge(in, peer); 00598 } 00599 /* If call has been answered, then the eventual hangup is likely to be normal hangup */ 00600 in->hangupcause = AST_CAUSE_NORMAL_CLEARING; 00601 c->hangupcause = AST_CAUSE_NORMAL_CLEARING; 00602 break; 00603 case AST_CONTROL_BUSY: 00604 if (option_verbose > 2) 00605 ast_verbose(VERBOSE_PREFIX_3 "%s is busy\n", c->name); 00606 in->hangupcause = c->hangupcause; 00607 ast_hangup(c); 00608 c = o->chan = NULL; 00609 ast_clear_flag(o, DIAL_STILLGOING); 00610 HANDLE_CAUSE(AST_CAUSE_BUSY, in); 00611 break; 00612 case AST_CONTROL_CONGESTION: 00613 if (option_verbose > 2) 00614 ast_verbose(VERBOSE_PREFIX_3 "%s is circuit-busy\n", c->name); 00615 in->hangupcause = c->hangupcause; 00616 ast_hangup(c); 00617 c = o->chan = NULL; 00618 ast_clear_flag(o, DIAL_STILLGOING); 00619 HANDLE_CAUSE(AST_CAUSE_CONGESTION, in); 00620 break; 00621 case AST_CONTROL_RINGING: 00622 if (ast_test_flag(peerflags, OPT_CALLBACK_INIT)) { 00623 if (option_verbose > 2) 00624 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing, hanging up.\n", o->chan->name); 00625 return NULL; 00626 } else { 00627 if (option_verbose > 2) 00628 ast_verbose(VERBOSE_PREFIX_3 "%s is ringing\n", c->name); 00629 /* Setup early media if appropriate */ 00630 if (single && CAN_EARLY_BRIDGE(peerflags)) 00631 ast_rtp_early_bridge(in, c); 00632 if (!(*sentringing) && !ast_test_flag(outgoing, OPT_MUSICBACK)) { 00633 ast_indicate(in, AST_CONTROL_RINGING); 00634 (*sentringing)++; 00635 } 00636 } 00637 break; 00638 case AST_CONTROL_PROGRESS: 00639 if (option_verbose > 2) 00640 ast_verbose (VERBOSE_PREFIX_3 "%s is making progress passing it to %s\n", c->name, in->name); 00641 /* Setup early media if appropriate */ 00642 if (single && CAN_EARLY_BRIDGE(peerflags)) 00643 ast_rtp_early_bridge(in, c); 00644 if (!ast_test_flag(outgoing, OPT_RINGBACK | OPT_NOINBAND)) 00645 ast_indicate(in, AST_CONTROL_PROGRESS); 00646 break; 00647 case AST_CONTROL_VIDUPDATE: 00648 if (option_verbose > 2) 00649 ast_verbose (VERBOSE_PREFIX_3 "%s requested a video update, passing it to %s\n", c->name, in->name); 00650 ast_indicate(in, AST_CONTROL_VIDUPDATE); 00651 break; 00652 case AST_CONTROL_PROCEEDING: 00653 if (option_verbose > 2) 00654 ast_verbose (VERBOSE_PREFIX_3 "%s is proceeding passing it to %s\n", c->name, in->name); 00655 if (single && CAN_EARLY_BRIDGE(peerflags)) 00656 ast_rtp_early_bridge(in, c); 00657 if (!ast_test_flag(outgoing, OPT_RINGBACK | OPT_NOINBAND)) 00658 ast_indicate(in, AST_CONTROL_PROCEEDING); 00659 break; 00660 case AST_CONTROL_HOLD: 00661 if (option_verbose > 2) 00662 ast_verbose(VERBOSE_PREFIX_3 "Call on %s placed on hold\n", c->name); 00663 ast_indicate(in, AST_CONTROL_HOLD); 00664 break; 00665 case AST_CONTROL_UNHOLD: 00666 if (option_verbose > 2) 00667 ast_verbose(VERBOSE_PREFIX_3 "Call on %s left from hold\n", c->name); 00668 ast_indicate(in, AST_CONTROL_UNHOLD); 00669 break; 00670 case AST_CONTROL_OFFHOOK: 00671 case AST_CONTROL_FLASH: 00672 /* Ignore going off hook and flash */ 00673 break; 00674 case -1: 00675 if (!ast_test_flag(outgoing, OPT_RINGBACK | OPT_MUSICBACK | OPT_NOINBAND)) { 00676 if (option_verbose > 2) 00677 ast_verbose(VERBOSE_PREFIX_3 "%s stopped sounds\n", c->name); 00678 ast_indicate(in, -1); 00679 (*sentringing) = 0; 00680 } 00681 break; 00682 default: 00683 if (option_debug) 00684 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass); 00685 } 00686 } else if (single) { 00687 /* XXX are we sure the logic is correct ? or we should just switch on f->frametype ? */ 00688 if (f->frametype == AST_FRAME_VOICE && !ast_test_flag(outgoing, OPT_RINGBACK|OPT_MUSICBACK)) { 00689 if (ast_write(in, f)) 00690 ast_log(LOG_WARNING, "Unable to forward voice frame\n"); 00691 } else if (f->frametype == AST_FRAME_IMAGE && !ast_test_flag(outgoing, OPT_RINGBACK|OPT_MUSICBACK)) { 00692 if (ast_write(in, f)) 00693 ast_log(LOG_WARNING, "Unable to forward image\n"); 00694 } else if (f->frametype == AST_FRAME_TEXT && !ast_test_flag(outgoing, OPT_RINGBACK|OPT_MUSICBACK)) { 00695 if (ast_write(in, f)) 00696 ast_log(LOG_WARNING, "Unable to send text\n"); 00697 } else if (f->frametype == AST_FRAME_HTML && !ast_test_flag(outgoing, DIAL_NOFORWARDHTML)) { 00698 if (ast_channel_sendhtml(in, f->subclass, f->data, f->datalen) == -1) 00699 ast_log(LOG_WARNING, "Unable to send URL\n"); 00700 } 00701 } 00702 ast_frfree(f); 00703 } /* end for */ 00704 if (winner == in) { 00705 struct ast_frame *f = ast_read(in); 00706 #if 0 00707 if (f && (f->frametype != AST_FRAME_VOICE)) 00708 printf("Frame type: %d, %d\n", f->frametype, f->subclass); 00709 else if (!f || (f->frametype != AST_FRAME_VOICE)) 00710 printf("Hangup received on %s\n", in->name); 00711 #endif 00712 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) { 00713 /* Got hung up */ 00714 *to = -1; 00715 ast_cdr_noanswer(in->cdr); 00716 strcpy(status, "CANCEL"); 00717 if (f) 00718 ast_frfree(f); 00719 return NULL; 00720 } 00721 00722 if (f && (f->frametype == AST_FRAME_DTMF)) { 00723 if (ast_test_flag(peerflags, OPT_DTMF_EXIT)) { 00724 const char *context = pbx_builtin_getvar_helper(in, "EXITCONTEXT"); 00725 if (onedigit_goto(in, context, (char) f->subclass, 1)) { 00726 if (option_verbose > 2) 00727 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass); 00728 *to=0; 00729 ast_cdr_noanswer(in->cdr); 00730 *result = f->subclass; 00731 strcpy(status, "CANCEL"); 00732 ast_frfree(f); 00733 return NULL; 00734 } 00735 } 00736 00737 if (ast_test_flag(peerflags, OPT_CALLER_HANGUP) && 00738 (f->subclass == '*')) { /* hmm it it not guaranteed to be '*' anymore. */ 00739 if (option_verbose > 2) 00740 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass); 00741 *to=0; 00742 ast_cdr_noanswer(in->cdr); 00743 strcpy(status, "CANCEL"); 00744 ast_frfree(f); 00745 return NULL; 00746 } 00747 } 00748 00749 /* Forward HTML stuff */ 00750 if (single && f && (f->frametype == AST_FRAME_HTML) && !ast_test_flag(outgoing, DIAL_NOFORWARDHTML)) 00751 if(ast_channel_sendhtml(outgoing->chan, f->subclass, f->data, f->datalen) == -1) 00752 ast_log(LOG_WARNING, "Unable to send URL\n"); 00753 00754 00755 if (single && ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_DTMF_BEGIN) || (f->frametype == AST_FRAME_DTMF_END))) { 00756 if (ast_write(outgoing->chan, f)) 00757 ast_log(LOG_WARNING, "Unable to forward voice or dtmf\n"); 00758 } 00759 if (single && (f->frametype == AST_FRAME_CONTROL) && 00760 ((f->subclass == AST_CONTROL_HOLD) || 00761 (f->subclass == AST_CONTROL_UNHOLD) || 00762 (f->subclass == AST_CONTROL_VIDUPDATE))) { 00763 if (option_verbose > 2) 00764 ast_verbose(VERBOSE_PREFIX_3 "%s requested special control %d, passing it to %s\n", in->name, f->subclass, outgoing->chan->name); 00765 ast_indicate_data(outgoing->chan, f->subclass, f->data, f->datalen); 00766 } 00767 ast_frfree(f); 00768 } 00769 if (!*to && (option_verbose > 2)) 00770 ast_verbose(VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig); 00771 if (!*to || ast_check_hangup(in)) { 00772 ast_cdr_noanswer(in->cdr); 00773 } 00774 00775 } 00776 if (peer && !ast_cdr_log_unanswered()) { 00777 /* suppress the CDR's that didn't win */ 00778 struct dial_localuser *o; 00779 for (o = outgoing; o; o = o->next) { 00780 struct ast_channel *c = o->chan; 00781 if (c && c != peer && c->cdr) { 00782 ast_set_flag(c->cdr, AST_CDR_FLAG_POST_DISABLED); 00783 } 00784 } 00785 } else if (!peer && !ast_cdr_log_unanswered()) { 00786 /* suppress the CDR's that didn't win */ 00787 struct dial_localuser *o; 00788 for (o = outgoing; o; o = o->next) { 00789 struct ast_channel *c = o->chan; 00790 if (c && c->cdr) { 00791 ast_set_flag(c->cdr, AST_CDR_FLAG_POST_DISABLED); 00792 } 00793 } 00794 } 00795 00796 return peer; 00797 }
char* app = "Dial" [static] |
Definition at line 71 of file app_dial.c.
char* descrip [static] |
Definition at line 75 of file app_dial.c.
enum { ... } dial_exec_option_args |
enum { ... } dial_exec_option_flags |
char* rapp = "RetryDial" [static] |
Definition at line 211 of file app_dial.c.
char* rdescrip [static] |
Definition at line 213 of file app_dial.c.
char* rsynopsis = "Place a call, retrying on failure allowing optional exit extension." [static] |
Definition at line 212 of file app_dial.c.
char* synopsis = "Place a call and connect to the current channel" [static] |
Definition at line 73 of file app_dial.c.