Merge anthm's RetryDial with changes (bug #3313)
authorMark Spencer <markster@digium.com>
Tue, 18 Jan 2005 03:12:53 +0000 (03:12 +0000)
committerMark Spencer <markster@digium.com>
Tue, 18 Jan 2005 03:12:53 +0000 (03:12 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@4828 65c4cc65-6c06-0410-ace0-fbb531ad65f3

apps/app_dial.c
doc/README.variables

index 1632388..6e1b5d8 100755 (executable)
@@ -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;
 }
 
index 4cf4245..b892556 100755 (executable)
@@ -103,6 +103,8 @@ ${QUEUE_PRIO}               Queue priority
 
 The following variables can be set to change certian behaviour:
 ${TOUCH_MONITOR}       The filename base to use with Touch Monitor (auto record)
+${EXITCONTEXT}         A context to consider in lieu of the curent context when
+                       dropping out of an attempted call into a 1 digit extension.
 
 The monitor application sets the following variable:
 ${MONITOR}             Set to "true" if the channel is/has been monitored.