aboutsummaryrefslogtreecommitdiffstats
path: root/apps/app_dial.c
diff options
context:
space:
mode:
authormarkster <markster@f38db490-d61c-443f-a65b-d21fe96a405b>2005-01-18 03:12:53 +0000
committermarkster <markster@f38db490-d61c-443f-a65b-d21fe96a405b>2005-01-18 03:12:53 +0000
commit6922e1676c196de2255dee00b0c467edcf647944 (patch)
tree11eed7f7473bd1e218ec92751bdc89d2888aaad1 /apps/app_dial.c
parentf2eedf346bdefac901a02f07c7623cdc4a721236 (diff)
Merge anthm's RetryDial with changes (bug #3313)
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@4828 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'apps/app_dial.c')
-rwxr-xr-xapps/app_dial.c289
1 files changed, 230 insertions, 59 deletions
diff --git a/apps/app_dial.c b/apps/app_dial.c
index 16323881c..6e1b5d836 100755
--- a/apps/app_dial.c
+++ b/apps/app_dial.c
@@ -60,6 +60,9 @@ static char *descrip =
" This application returns -1 if the originating channel hangs up, or if the\n"
"call is bridged and either of the parties in the bridge terminate the call.\n"
"The option string may contain zero or more of the following characters:\n"
+" 'd' -- allow the calling user to dial a 1 digit extension while waiting for a call to\n"
+" be answered exiting to that extension if it exists in the context defined by\n"
+" ${EXITCONTEXT} or the current context.\n"
" 't' -- allow the called user to transfer the calling user by hitting #.\n"
" 'T' -- allow the calling user to transfer the call by hitting #.\n"
" 'w' -- allow the called user to write the conversation to disk via app_monitor\n"
@@ -111,21 +114,37 @@ static char *descrip =
" CHANUNAVAIL | CONGESTION | NOANSWER | BUSY | ANSWER | CANCEL\n"
"";
+/* RetryDial App by Anthony Minessale II <anthmct@yahoo.com> Jan/2005 */
+static char *rapp = "RetryDial";
+static char *rsynopsis = "Place a call, retrying on failure allowing optional exit extension.\n";
+static char *rdescrip =
+" RetryDial(announce|sleep|loops|Technology/resource[&Technology2/resource2...][|timeout][|options][|URL]):\n"
+"Attempt to place a call. If no channel can be reached, play the file defined by 'announce'\n"
+"waiting 'sleep' seconds to retry the call. If the specified number of attempts matches \n"
+"'loops' the call will continue in the dialplan. If 'loops' is set to 0, the call will retry endlessly.\n\n"
+"While waiting, a 1 digit extension may be dialed. If that extension exists in either\n"
+"the context defined in ${EXITCONTEXT} or the current one, The call will transfer\n"
+"to that extension immmediately.\n\n"
+"All arguements after 'loops' are passed directly to the Dial() application.\n"
+"";
+
+
/* We define a customer "local user" structure because we
use it not only for keeping track of what is in use but
also for keeping track of who we're dialing. */
-#define DIAL_STILLGOING (1 << 0)
+#define DIAL_STILLGOING (1 << 0)
#define DIAL_ALLOWREDIRECT_IN (1 << 1)
#define DIAL_ALLOWREDIRECT_OUT (1 << 2)
#define DIAL_ALLOWDISCONNECT_IN (1 << 3)
#define DIAL_ALLOWDISCONNECT_OUT (1 << 4)
-#define DIAL_RINGBACKONLY (1 << 5)
-#define DIAL_MUSICONHOLD (1 << 6)
-#define DIAL_FORCECALLERID (1 << 7)
-#define DIAL_MONITOR_IN (1 << 8)
-#define DIAL_MONITOR_OUT (1 << 9)
-#define DIAL_GO_ON (1 << 10)
+#define DIAL_RINGBACKONLY (1 << 5)
+#define DIAL_MUSICONHOLD (1 << 6)
+#define DIAL_FORCECALLERID (1 << 7)
+#define DIAL_MONITOR_IN (1 << 8)
+#define DIAL_MONITOR_OUT (1 << 9)
+#define DIAL_GO_ON (1 << 10)
+#define DIAL_HALT_ON_DTMF (1 << 11)
struct localuser {
struct ast_channel *chan;
@@ -140,7 +159,7 @@ static void hanguptree(struct localuser *outgoing, struct ast_channel *exception
{
/* Hang up a tree of stuff */
struct localuser *oo;
- while(outgoing) {
+ while (outgoing) {
/* Hangup any existing lines we have open */
if (outgoing->chan && (outgoing->chan != exception))
ast_hangup(outgoing->chan);
@@ -171,10 +190,34 @@ static void hanguptree(struct localuser *outgoing, struct ast_channel *exception
numnochan++; \
break; \
} \
-} while(0)
+} while (0)
+
+
+static int ast_onedigit_goto(struct ast_channel *chan, char *context, char exten, int pri, char *cid)
+{
+ char rexten[2];
+ snprintf(rexten, 2, "%c", exten);
+ if (context) {
+ if (ast_exists_extension(chan, context, rexten, pri, cid)) {
+ ast_explicit_goto(chan, context, rexten, pri-1);
+ return 1;
+ }
+ } else {
+ if (ast_exists_extension(chan, chan->context, rexten, pri, cid)) {
+ ast_explicit_goto(chan, chan->context, rexten, pri-1);
+ return 1;
+ } else if (!ast_strlen_zero(chan->macrocontext)) {
+ if (ast_exists_extension(chan, chan->context, rexten, pri, cid)) {
+ ast_explicit_goto(chan, chan->context, rexten, pri-1);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
-static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localuser *outgoing, int *to, struct ast_flags *peerflags, int *sentringing, char *status, size_t statussize, int busystart, int nochanstart, int congestionstart)
+static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localuser *outgoing, int *to, struct ast_flags *peerflags, int *sentringing, char *status, size_t statussize, int busystart, int nochanstart, int congestionstart, int *result)
{
struct localuser *o;
int found;
@@ -191,7 +234,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu
int pos;
int single;
struct ast_channel *winner;
-
+ char *context = NULL;
+
single = (outgoing && !outgoing->next && !ast_test_flag(outgoing, DIAL_MUSICONHOLD | DIAL_RINGBACKONLY));
if (single) {
@@ -202,13 +246,13 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu
}
- while(*to && !peer) {
+ while (*to && !peer) {
o = outgoing;
found = -1;
pos = 1;
numlines = prestart;
watchers[0] = in;
- while(o) {
+ while (o) {
/* Keep track of important channels */
if (ast_test_flag(o, DIAL_STILLGOING) && o->chan) {
watchers[pos++] = o->chan;
@@ -239,7 +283,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu
}
winner = ast_waitfor_n(watchers, pos, to);
o = outgoing;
- while(o) {
+ while (o) {
if (ast_test_flag(o, DIAL_STILLGOING) && o->chan && (o->chan->_state == AST_STATE_UP)) {
if (!peer) {
if (option_verbose > 2)
@@ -453,15 +497,32 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu
ast_frfree(f);
return NULL;
}
- if (f && (f->frametype == AST_FRAME_DTMF) && ast_test_flag(peerflags, DIAL_ALLOWDISCONNECT_OUT) &&
- (f->subclass == '*')) {
- if (option_verbose > 3)
- ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
- *to=0;
- strcpy(status, "CANCEL");
- ast_frfree(f);
- return NULL;
+
+ if (f && (f->frametype == AST_FRAME_DTMF)) {
+ if (ast_test_flag(peerflags, DIAL_HALT_ON_DTMF)) {
+ context = pbx_builtin_getvar_helper(in, "EXITCONTEXT");
+ if (ast_onedigit_goto(in, context, (char) f->subclass, 1, in->cid.cid_num)) {
+ if (option_verbose > 3)
+ ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
+ *to=0;
+ *result = f->subclass;
+ strcpy(status, "CANCEL");
+ ast_frfree(f);
+ return NULL;
+ }
+ }
+
+ if (ast_test_flag(peerflags, DIAL_ALLOWDISCONNECT_OUT) &&
+ (f->subclass == '*')) { /* hmm it it not guarenteed to be '*' anymore. */
+ if (option_verbose > 3)
+ ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
+ *to=0;
+ strcpy(status, "CANCEL");
+ ast_frfree(f);
+ return NULL;
+ }
}
+
if (single && ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_DTMF))) {
if (ast_write(outgoing->chan, f))
ast_log(LOG_WARNING, "Unable to forward voice\n");
@@ -476,7 +537,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu
}
-static int dial_exec(struct ast_channel *chan, void *data)
+
+static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags *peerflags)
{
int res=-1;
struct localuser *u;
@@ -486,7 +548,6 @@ static int dial_exec(struct ast_channel *chan, void *data)
struct localuser *outgoing=NULL, *tmp;
struct ast_channel *peer;
int to;
- struct ast_flags peerflags={0};
int hasmacro = 0;
int privacy=0;
int announce=0;
@@ -524,10 +585,10 @@ static int dial_exec(struct ast_channel *chan, void *data)
char *mohclass = NULL;
char *outbound_group = NULL;
char *macro_result = NULL, *macro_transfer_dest = NULL;
- int digit = 0;
+ int digit = 0, result = 0;
time_t start_time, answer_time, end_time;
struct ast_app *app = NULL;
-
+
if (!data) {
ast_log(LOG_WARNING, "Dial requires an argument (technology1/number1&technology2/number2...|optional timeout|options)\n");
return -1;
@@ -601,7 +662,7 @@ static int dial_exec(struct ast_channel *chan, void *data)
if ((limitptr = strstr(transfer, "L("))) {
strncpy(limitdata, limitptr + 2, sizeof(limitdata) - 1);
/* Overwrite with X's what was the limit info */
- while(*limitptr && (*limitptr != ')'))
+ while (*limitptr && (*limitptr != ')'))
*(limitptr++) = 'X';
if (*limitptr)
*limitptr = 'X';
@@ -641,7 +702,7 @@ static int dial_exec(struct ast_channel *chan, void *data)
play_warning = atol(var);
playargs++;
var = strsep(&stack, ":");
- if(var) {
+ if (var) {
warning_freq = atol(var);
playargs++;
}
@@ -676,7 +737,7 @@ static int dial_exec(struct ast_channel *chan, void *data)
announce = 1;
strncpy(announcemsg, ann + 2, sizeof(announcemsg) - 1);
/* Overwrite with X's what was the announce info */
- while(*ann && (*ann != ')'))
+ while (*ann && (*ann != ')'))
*(ann++) = 'X';
if (*ann)
*ann = 'X';
@@ -735,7 +796,7 @@ static int dial_exec(struct ast_channel *chan, void *data)
privacy = 1;
strncpy(privdb, s + 2, sizeof(privdb) - 1);
/* Overwrite with X's what was the privacy info */
- while(*s && (*s != ')'))
+ while (*s && (*s != ')'))
*(s++) = 'X';
if (*s)
*s = 'X';
@@ -799,12 +860,13 @@ static int dial_exec(struct ast_channel *chan, void *data)
ast_set2_flag(tmp, strchr(transfer, 'r'), DIAL_RINGBACKONLY);
ast_set2_flag(tmp, strchr(transfer, 'm'), DIAL_MUSICONHOLD);
ast_set2_flag(tmp, strchr(transfer, 'H'), DIAL_ALLOWDISCONNECT_OUT);
- ast_set2_flag(&peerflags, strchr(transfer, 'H'), DIAL_ALLOWDISCONNECT_OUT);
+ ast_set2_flag(peerflags, strchr(transfer, 'H'), DIAL_ALLOWDISCONNECT_OUT);
ast_set2_flag(tmp, strchr(transfer, 'h'), DIAL_ALLOWDISCONNECT_IN);
- ast_set2_flag(&peerflags, strchr(transfer, 'h'), DIAL_ALLOWDISCONNECT_IN);
+ ast_set2_flag(peerflags, strchr(transfer, 'h'), DIAL_ALLOWDISCONNECT_IN);
ast_set2_flag(tmp, strchr(transfer, 'f'), DIAL_FORCECALLERID);
- ast_set2_flag(&peerflags, strchr(transfer, 'w'), DIAL_MONITOR_IN);
- ast_set2_flag(&peerflags, strchr(transfer, 'W'), DIAL_MONITOR_OUT);
+ ast_set2_flag(peerflags, strchr(transfer, 'w'), DIAL_MONITOR_IN);
+ ast_set2_flag(peerflags, strchr(transfer, 'W'), DIAL_MONITOR_OUT);
+ ast_set2_flag(peerflags, strchr(transfer, 'd'), DIAL_HALT_ON_DTMF);
ast_set2_flag(tmp, strchr(transfer, 'g'), DIAL_GO_ON);
}
strncpy(numsubst, number, sizeof(numsubst)-1);
@@ -940,7 +1002,7 @@ static int dial_exec(struct ast_channel *chan, void *data)
if (outgoing->chan->_state == AST_STATE_UP)
break;
cur = rest;
- } while(cur);
+ } while (cur);
if (timeout && !ast_strlen_zero(timeout)) {
to = atoi(timeout);
@@ -965,13 +1027,16 @@ static int dial_exec(struct ast_channel *chan, void *data)
strncpy(status, "CHANUNAVAIL", sizeof(status) - 1);
time(&start_time);
- peer = wait_for_answer(chan, outgoing, &to, &peerflags, &sentringing, status, sizeof(status), numbusy, numnochan, numcongestion);
+ peer = wait_for_answer(chan, outgoing, &to, peerflags, &sentringing, status, sizeof(status), numbusy, numnochan, numcongestion, &result);
if (!peer) {
- if (to)
+ if (result) {
+ res = result;
+ }
+ else if (to)
/* Musta gotten hung up */
res = -1;
- else
+ else
/* Nobody answered, next please? */
res=0;
@@ -997,7 +1062,7 @@ static int dial_exec(struct ast_channel *chan, void *data)
if (numsubst)
pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", numsubst);
/* JDG: sendurl */
- if( url && !ast_strlen_zero(url) && ast_channel_supports_html(peer) ) {
+ if ( url && !ast_strlen_zero(url) && ast_channel_supports_html(peer) ) {
ast_log(LOG_DEBUG, "app_dial: sendurl=%s.\n", url);
ast_channel_sendurl( peer, url );
} /* /JDG */
@@ -1030,8 +1095,8 @@ static int dial_exec(struct ast_channel *chan, void *data)
app = pbx_findapp("Macro");
if (app && !res) {
- for(res=0;res<strlen(macroname);res++)
- if(macroname[res] == '^')
+ for (res=0;res<strlen(macroname);res++)
+ if (macroname[res] == '^')
macroname[res] = '|';
res = pbx_exec(peer, app, macroname, 1);
ast_log(LOG_DEBUG, "Macro exited with status %d\n", res);
@@ -1051,13 +1116,13 @@ static int dial_exec(struct ast_channel *chan, void *data)
if (!strcasecmp(macro_result, "BUSY")) {
strncpy(status, macro_result, sizeof(status) - 1);
if (!ast_goto_if_exists(chan, NULL, NULL, chan->priority + 101)) {
- ast_set_flag(&peerflags, DIAL_GO_ON);
+ ast_set_flag(peerflags, DIAL_GO_ON);
}
res = -1;
}
else if (!strcasecmp(macro_result, "CONGESTION") || !strcasecmp(macro_result, "CHANUNAVAIL")) {
strncpy(status, macro_result, sizeof(status) - 1);
- ast_set_flag(&peerflags, DIAL_GO_ON);
+ ast_set_flag(peerflags, DIAL_GO_ON);
res = -1;
}
else if (!strcasecmp(macro_result, "CONTINUE")) {
@@ -1065,22 +1130,22 @@ static int dial_exec(struct ast_channel *chan, void *data)
the context / exten / priority or perhaps
the next priority in the current exten is desired.
*/
- ast_set_flag(&peerflags, DIAL_GO_ON);
+ ast_set_flag(peerflags, DIAL_GO_ON);
res = -1;
} else if (!strcasecmp(macro_result, "ABORT")) {
/* Hangup both ends unless the caller has the g flag */
res = -1;
- } else if(!strncasecmp(macro_result, "GOTO:",5) && (macro_transfer_dest = ast_strdupa(macro_result + 5))) {
+ } else if (!strncasecmp(macro_result, "GOTO:",5) && (macro_transfer_dest = ast_strdupa(macro_result + 5))) {
res = -1;
/* perform a transfer to a new extension */
- if(strchr(macro_transfer_dest,'^')) { /* context^exten^priority*/
+ if (strchr(macro_transfer_dest,'^')) { /* context^exten^priority*/
/* no brainer mode... substitute ^ with | and feed it to builtin goto */
- for(res=0;res<strlen(macro_transfer_dest);res++)
- if(macro_transfer_dest[res] == '^')
+ for (res=0;res<strlen(macro_transfer_dest);res++)
+ if (macro_transfer_dest[res] == '^')
macro_transfer_dest[res] = '|';
- if(!ast_parseable_goto(chan, macro_transfer_dest))
- ast_set_flag(&peerflags, DIAL_GO_ON);
+ if (!ast_parseable_goto(chan, macro_transfer_dest))
+ ast_set_flag(peerflags, DIAL_GO_ON);
}
}
@@ -1103,18 +1168,19 @@ static int dial_exec(struct ast_channel *chan, void *data)
ast_set_flag(&(config.features_caller), AST_FEATURE_PLAY_WARNING);
if (play_to_callee)
ast_set_flag(&(config.features_callee), AST_FEATURE_PLAY_WARNING);
- if (ast_test_flag(&peerflags, DIAL_ALLOWREDIRECT_IN))
+ if (ast_test_flag(peerflags, DIAL_ALLOWREDIRECT_IN))
ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
- if (ast_test_flag(&peerflags, DIAL_ALLOWREDIRECT_OUT))
+ if (ast_test_flag(peerflags, DIAL_ALLOWREDIRECT_OUT))
ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
- if (ast_test_flag(&peerflags, DIAL_ALLOWDISCONNECT_IN))
+ if (ast_test_flag(peerflags, DIAL_ALLOWDISCONNECT_IN))
ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
- if (ast_test_flag(&peerflags, DIAL_ALLOWDISCONNECT_OUT))
+ if (ast_test_flag(peerflags, DIAL_ALLOWDISCONNECT_OUT))
ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
- if (ast_test_flag(&peerflags, DIAL_MONITOR_IN))
+ if (ast_test_flag(peerflags, DIAL_MONITOR_IN))
ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
- if (ast_test_flag(&peerflags, DIAL_MONITOR_OUT))
+ if (ast_test_flag(peerflags, DIAL_MONITOR_OUT))
ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
+
config.timelimit = timelimit;
config.play_warning = play_warning;
config.warning_freq = warning_freq;
@@ -1167,22 +1233,127 @@ out:
LOCAL_USER_REMOVE(u);
- if((ast_test_flag(&peerflags, DIAL_GO_ON)) && (!chan->_softhangup))
+ if ((ast_test_flag(peerflags, DIAL_GO_ON)) && (!chan->_softhangup))
res=0;
return res;
}
+static int dial_exec(struct ast_channel *chan, void *data)
+{
+ struct ast_flags peerflags;
+ memset(&peerflags, 0, sizeof(peerflags));
+ return dial_exec_full(chan, data, &peerflags);
+}
+
+static int retrydial_exec(struct ast_channel *chan, void *data)
+{
+ char *announce = NULL, *context = NULL, *dialdata = NULL;
+ int sleep = 0, loops = 0, res = 0;
+ struct localuser *u = NULL;
+ struct ast_flags peerflags;
+
+ memset(&peerflags, 0, sizeof(peerflags));
+
+ LOCAL_USER_ADD(u);
+
+ if (!data || !(announce = ast_strdupa(data))) {
+ ast_log(LOG_ERROR, "Out of memory!\n");
+ LOCAL_USER_REMOVE(u);
+ return -1;
+ }
+
+ if ((dialdata = strchr(announce, '|'))) {
+ *dialdata = '\0';
+ dialdata++;
+ if ((sleep = atoi(dialdata))) {
+ sleep *= 1000;
+ } else {
+ ast_log(LOG_ERROR, "%s requires the numrical arguement <sleep>\n",rapp);
+ LOCAL_USER_REMOVE(u);
+ return -1;
+ }
+ if ((dialdata = strchr(dialdata, '|'))) {
+ *dialdata = '\0';
+ dialdata++;
+ if (!(loops = atoi(dialdata))) {
+ ast_log(LOG_ERROR, "%s requires the numrical arguement <loops>\n",rapp);
+ LOCAL_USER_REMOVE(u);
+ return -1;
+ }
+ }
+ }
+
+ if ((dialdata = strchr(dialdata, '|'))) {
+ *dialdata = '\0';
+ dialdata++;
+ } else {
+ ast_log(LOG_ERROR, "%s requires more arguements\n",rapp);
+ LOCAL_USER_REMOVE(u);
+ return -1;
+ }
+
+ if (sleep < 1000)
+ sleep = 10000;
+
+ if (!loops)
+ loops = -1;
+
+ context = pbx_builtin_getvar_helper(chan, "EXITCONTEXT");
+
+ while (loops) {
+ chan->data = "Retrying";
+ if (ast_test_flag(chan, AST_FLAG_MOH))
+ ast_moh_stop(chan);
+
+ if ((res = dial_exec(chan, dialdata)) == 0) {
+ if (ast_test_flag(&peerflags, DIAL_HALT_ON_DTMF)) {
+ if (!(res = ast_streamfile(chan, announce, chan->language)))
+ res = ast_waitstream(chan, AST_DIGIT_ANY);
+ if (!res) {
+ if (!ast_test_flag(chan, AST_FLAG_MOH))
+ ast_moh_start(chan, NULL);
+ res = ast_waitfordigit(chan, sleep);
+ }
+ } else {
+ if (!(res = ast_streamfile(chan, announce, chan->language)))
+ res = ast_waitstream(chan, "");
+ if (!res)
+ res = ast_safe_sleep(chan, sleep);
+ }
+ }
+
+ if (res < 0)
+ break;
+ else if (res > 0) { /* Trying to send the call elsewhere (1 digit ext) */
+ if (ast_onedigit_goto(chan, context, (char) res, 1, chan->cid.cid_num)) {
+ res = 0;
+ break;
+ }
+ }
+ loops--;
+ }
+
+ if (ast_test_flag(chan, AST_FLAG_MOH))
+ ast_moh_stop(chan);
+
+ LOCAL_USER_REMOVE(u);
+ return loops ? res : 0;
+
+}
+
int unload_module(void)
{
STANDARD_HANGUP_LOCALUSERS;
- return ast_unregister_application(app);
+ ast_unregister_application(app);
+ return ast_unregister_application(rapp);
}
int load_module(void)
{
int res;
- res = ast_register_application(app, dial_exec, synopsis, descrip);
+ if (!(res = ast_register_application(app, dial_exec, synopsis, descrip)))
+ res = ast_register_application(rapp, retrydial_exec, rsynopsis, rdescrip);
return res;
}