Fri Feb 19 17:12:32 2010

Asterisk developer's documentation


app_dial.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief dial() & retrydial() - Trivial application to dial a channel and send an URL on answer
00022  *
00023  * \author Mark Spencer <markster@digium.com>
00024  * 
00025  * \ingroup applications
00026  */
00027 
00028 /*** MODULEINFO
00029         <depend>chan_local</depend>
00030  ***/
00031 
00032 
00033 #include "asterisk.h"
00034 
00035 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 231235 $")
00036 
00037 #include <stdlib.h>
00038 #include <errno.h>
00039 #include <unistd.h>
00040 #include <string.h>
00041 #include <stdlib.h>
00042 #include <stdio.h>
00043 #include <sys/time.h>
00044 #include <sys/signal.h>
00045 #include <sys/stat.h>
00046 #include <netinet/in.h>
00047 
00048 #include "asterisk/lock.h"
00049 #include "asterisk/file.h"
00050 #include "asterisk/logger.h"
00051 #include "asterisk/channel.h"
00052 #include "asterisk/pbx.h"
00053 #include "asterisk/options.h"
00054 #include "asterisk/module.h"
00055 #include "asterisk/translate.h"
00056 #include "asterisk/say.h"
00057 #include "asterisk/config.h"
00058 #include "asterisk/features.h"
00059 #include "asterisk/musiconhold.h"
00060 #include "asterisk/callerid.h"
00061 #include "asterisk/utils.h"
00062 #include "asterisk/app.h"
00063 #include "asterisk/causes.h"
00064 #include "asterisk/rtp.h"
00065 #include "asterisk/cdr.h"
00066 #include "asterisk/manager.h"
00067 #include "asterisk/privacy.h"
00068 #include "asterisk/stringfields.h"
00069 #include "asterisk/global_datastores.h"
00070 
00071 static char *app = "Dial";
00072 
00073 static char *synopsis = "Place a call and connect to the current channel";
00074 
00075 static char *descrip =
00076 "  Dial(Technology/resource[&Tech2/resource2...][|timeout][|options][|URL]):\n"
00077 "This application will place calls to one or more specified channels. As soon\n"
00078 "as one of the requested channels answers, the originating channel will be\n"
00079 "answered, if it has not already been answered. These two channels will then\n"
00080 "be active in a bridged call. All other channels that were requested will then\n"
00081 "be hung up.\n"
00082 "  Unless there is a timeout specified, the Dial application will wait\n"
00083 "indefinitely until one of the called channels answers, the user hangs up, or\n"
00084 "if all of the called channels are busy or unavailable. Dialplan executing will\n"
00085 "continue if no requested channels can be called, or if the timeout expires.\n\n"
00086 "  This application sets the following channel variables upon completion:\n"
00087 "    DIALEDTIME   - This is the time from dialing a channel until when it\n"
00088 "                   is disconnected.\n" 
00089 "    ANSWEREDTIME - This is the amount of time for actual call.\n"
00090 "    DIALSTATUS   - This is the status of the call:\n"
00091 "                   CHANUNAVAIL | CONGESTION | NOANSWER | BUSY | ANSWER | CANCEL\n" 
00092 "                   DONTCALL | TORTURE | INVALIDARGS\n"
00093 "  For the Privacy and Screening Modes, the DIALSTATUS variable will be set to\n"
00094 "DONTCALL if the called party chooses to send the calling party to the 'Go Away'\n"
00095 "script. The DIALSTATUS variable will be set to TORTURE if the called party\n"
00096 "wants to send the caller to the 'torture' script.\n"
00097 "  This application will report normal termination if the originating channel\n"
00098 "hangs up, or if the call is bridged and either of the parties in the bridge\n"
00099 "ends the call.\n"
00100 "  The optional URL will be sent to the called party if the channel supports it.\n"
00101 "  If the OUTBOUND_GROUP variable is set, all peer channels created by this\n"
00102 "application will be put into that group (as in Set(GROUP()=...).\n"
00103 "  If the OUTBOUND_GROUP_ONCE variable is set, all peer channels created by this\n"
00104 "application will be put into that group (as in Set(GROUP()=...). Unlike OUTBOUND_GROUP,\n"
00105 "however, the variable will be unset after use.\n\n"
00106 "  Options:\n"
00107 "    A(x) - Play an announcement to the called party, using 'x' as the file.\n"
00108 "    C    - Reset the CDR for this call.\n"
00109 "    d    - Allow the calling user to dial a 1 digit extension while waiting for\n"
00110 "           a call to be answered. Exit to that extension if it exists in the\n"
00111 "           current context, or the context defined in the EXITCONTEXT variable,\n"
00112 "           if it exists.\n"
00113 "    D([called][:calling]) - Send the specified DTMF strings *after* the called\n"
00114 "           party has answered, but before the call gets bridged. The 'called'\n"
00115 "           DTMF string is sent to the called party, and the 'calling' DTMF\n"
00116 "           string is sent to the calling party. Both parameters can be used\n"
00117 "           alone.\n"   
00118 "    f    - Force the callerid of the *calling* channel to be set as the\n"
00119 "           extension associated with the channel using a dialplan 'hint'.\n"
00120 "           For example, some PSTNs do not allow CallerID to be set to anything\n"
00121 "           other than the number assigned to the caller.\n"
00122 "    g    - Proceed with dialplan execution at the current extension if the\n"
00123 "           destination channel hangs up.\n"
00124 "    G(context^exten^pri) - If the call is answered, transfer the calling party to\n"
00125 "           the specified priority and the called party to the specified priority+1.\n"
00126 "           Optionally, an extension, or extension and context may be specified. \n"
00127 "           Otherwise, the current extension is used. You cannot use any additional\n"
00128 "           action post answer options in conjunction with this option.\n" 
00129 "    h    - Allow the called party to hang up by sending the '*' DTMF digit, or\n"
00130 "           whatever sequence was defined in the featuremap section for\n"
00131 "           'disconnect' in features.conf\n"
00132 "    H    - Allow the calling party to hang up by hitting the '*' DTMF digit, or\n"
00133 "           whatever sequence was defined in the featuremap section for\n"
00134 "           'disconnect' in features.conf\n"
00135 "    i    - Asterisk will ignore any forwarding requests it may receive on this\n"
00136 "           dial attempt.\n"
00137 "    j    - Jump to priority n+101 if all of the requested channels were busy.\n"
00138 "    k    - Allow the called party to enable parking of the call by sending\n"
00139 "           the DTMF sequence defined for call parking in the featuremap section of features.conf.\n"
00140 "    K    - Allow the calling party to enable parking of the call by sending\n"
00141 "           the DTMF sequence defined for call parking in the featuremap section of features.conf.\n"
00142 "    L(x[:y][:z]) - Limit the call to 'x' ms. Play a warning when 'y' ms are\n"
00143 "           left. Repeat the warning every 'z' ms. The following special\n"
00144 "           variables can be used with this option:\n"
00145 "           * LIMIT_PLAYAUDIO_CALLER   yes|no (default yes)\n"
00146 "                                      Play sounds to the caller.\n"
00147 "           * LIMIT_PLAYAUDIO_CALLEE   yes|no\n"
00148 "                                      Play sounds to the callee.\n"
00149 "           * LIMIT_TIMEOUT_FILE       File to play when time is up.\n"
00150 "           * LIMIT_CONNECT_FILE       File to play when call begins.\n"
00151 "           * LIMIT_WARNING_FILE       File to play as warning if 'y' is defined.\n"
00152 "                                      The default is to say the time remaining.\n"
00153 "    m([class]) - Provide hold music to the calling party until a requested\n"
00154 "           channel answers. A specific MusicOnHold class can be\n"
00155 "           specified.\n"
00156 "    M(x[^arg]) - Execute the Macro for the *called* channel before connecting\n"
00157 "           to the calling channel. Arguments can be specified to the Macro\n"
00158 "           using '^' as a delimeter. The Macro can set the variable\n"
00159 "           MACRO_RESULT to specify the following actions after the Macro is\n" 
00160 "           finished executing.\n"
00161 "           * ABORT        Hangup both legs of the call.\n"
00162 "           * CONGESTION   Behave as if line congestion was encountered.\n"
00163 "           * BUSY         Behave as if a busy signal was encountered. This will also\n"
00164 "                          have the application jump to priority n+101 if the\n"
00165 "                          'j' option is set.\n"
00166 "           * CONTINUE     Hangup the called party and allow the calling party\n"
00167 "                          to continue dialplan execution at the next priority.\n"
00168 "           * GOTO:<context>^<exten>^<priority> - Transfer the call to the\n"
00169 "                          specified priority. Optionally, an extension, or\n"
00170 "                          extension and priority can be specified.\n"
00171 "           You cannot use any additional action post answer options in conjunction\n"
00172 "           with this option. Also, pbx services are not run on the peer (called) channel,\n"
00173 "           so you will not be able to set timeouts via the TIMEOUT() function in this macro.\n"
00174 "    n([x]) - This option is a modifier for the screen/privacy mode. It specifies\n"
00175 "             that no introductions are to be saved in the priv-callerintros\n"
00176 "             directory.\n"
00177 "             Specified without an arg, or with 0, the introduction is saved after\n"
00178 "             an unanswered call originating from the same CallerID. With\n"
00179 "             a 1 specified, the introduction is always deleted and rerequested.\n"
00180 "    N    - This option is a modifier for the screen/privacy mode. It specifies\n"
00181 "           that if callerID is present, do not screen the call.\n"
00182 "    o    - Specify that the CallerID that was present on the *calling* channel\n"
00183 "           be set as the CallerID on the *called* channel. This was the\n"
00184 "           behavior of Asterisk 1.0 and earlier.\n"
00185 "    O([x]) - \"Operator Services\" mode (Zaptel channel to Zaptel channel\n"
00186 "             only, if specified on non-Zaptel interface, it will be ignored).\n"
00187 "             When the destination answers (presumably an operator services\n"
00188 "             station), the originator no longer has control of their line.\n"
00189 "             They may hang up, but the switch will not release their line\n"
00190 "             until the destination party hangs up (the operator). Specified\n"
00191 "             without an arg, or with 1 as an arg, the originator hanging up\n"
00192 "             will cause the phone to ring back immediately. With a 2 specified,\n"
00193 "             when the \"operator\" flashes the trunk, it will ring their phone\n"
00194 "             back.\n"
00195 "    p    - This option enables screening mode. This is basically Privacy mode\n"
00196 "           without memory.\n"
00197 "    P([x]) - Enable privacy mode. Use 'x' as the family/key in the database if\n"
00198 "           it is provided. The current extension is used if a database\n"
00199 "           family/key is not specified.\n"
00200 "    r    - Indicate ringing to the calling party. Pass no audio to the calling\n"
00201 "           party until the called channel has answered.\n"
00202 "    S(x) - Hang up the call after 'x' seconds *after* the called party has\n"
00203 "           answered the call.\n"   
00204 "    t    - Allow the called party to transfer the calling party by sending the\n"
00205 "           DTMF sequence defined in the blindxfer setting in the featuremap section\n"
00206 "           of features.conf.\n"
00207 "    T    - Allow the calling party to transfer the called party by sending the\n"
00208 "           DTMF sequence defined in the blindxfer setting in the featuremap section\n"
00209 "           of features.conf.\n"
00210 "    w    - Allow the called party to enable recording of the call by sending\n"
00211 "           the DTMF sequence defined in the automon setting in the featuremap section\n"
00212 "           of features.conf.\n"
00213 "    W    - Allow the calling party to enable recording of the call by sending\n"
00214 "           the DTMF sequence defined in the automon setting in the featuremap section\n"
00215 "           of features.conf.\n";
00216 
00217 /* RetryDial App by Anthony Minessale II <anthmct@yahoo.com> Jan/2005 */
00218 static char *rapp = "RetryDial";
00219 static char *rsynopsis = "Place a call, retrying on failure allowing optional exit extension.";
00220 static char *rdescrip =
00221 "  RetryDial(announce|sleep|retries|dialargs): This application will attempt to\n"
00222 "place a call using the normal Dial application. If no channel can be reached,\n"
00223 "the 'announce' file will be played. Then, it will wait 'sleep' number of\n"
00224 "seconds before retrying the call. After 'retries' number of attempts, the\n"
00225 "calling channel will continue at the next priority in the dialplan. If the\n"
00226 "'retries' setting is set to 0, this application will retry endlessly.\n"
00227 "  While waiting to retry a call, a 1 digit extension may be dialed. If that\n"
00228 "extension exists in either the context defined in ${EXITCONTEXT} or the current\n"
00229 "one, The call will jump to that extension immediately.\n"
00230 "  The 'dialargs' are specified in the same format that arguments are provided\n"
00231 "to the Dial application.\n";
00232 
00233 enum {
00234    OPT_ANNOUNCE =    (1 << 0),
00235    OPT_RESETCDR =    (1 << 1),
00236    OPT_DTMF_EXIT =      (1 << 2),
00237    OPT_SENDDTMF =    (1 << 3),
00238    OPT_FORCECLID =      (1 << 4),
00239    OPT_GO_ON =    (1 << 5),
00240    OPT_CALLEE_HANGUP =  (1 << 6),
00241    OPT_CALLER_HANGUP =  (1 << 7),
00242    OPT_PRIORITY_JUMP =  (1 << 8),
00243    OPT_DURATION_LIMIT = (1 << 9),
00244    OPT_MUSICBACK =      (1 << 10),
00245    OPT_CALLEE_MACRO =   (1 << 11),
00246    OPT_SCREEN_NOINTRO = (1 << 12),
00247    OPT_SCREEN_NOCLID =  (1 << 13),
00248    OPT_ORIGINAL_CLID =  (1 << 14),
00249    OPT_SCREENING =      (1 << 15),
00250    OPT_PRIVACY =     (1 << 16),
00251    OPT_RINGBACK =    (1 << 17),
00252    OPT_DURATION_STOP =  (1 << 18),
00253    OPT_CALLEE_TRANSFER =   (1 << 19),
00254    OPT_CALLER_TRANSFER =   (1 << 20),
00255    OPT_CALLEE_MONITOR = (1 << 21),
00256    OPT_CALLER_MONITOR = (1 << 22),
00257    OPT_GOTO =     (1 << 23),
00258    OPT_OPERMODE =       (1 << 24),
00259    OPT_CALLEE_PARK = (1 << 25),
00260    OPT_CALLER_PARK = (1 << 26),
00261    OPT_IGNORE_FORWARDING = (1 << 27),
00262 } dial_exec_option_flags;
00263 
00264 #define DIAL_STILLGOING       (1 << 30)
00265 #define DIAL_NOFORWARDHTML    (1 << 31)
00266 
00267 enum {
00268    OPT_ARG_ANNOUNCE = 0,
00269    OPT_ARG_SENDDTMF,
00270    OPT_ARG_GOTO,
00271    OPT_ARG_DURATION_LIMIT,
00272    OPT_ARG_MUSICBACK,
00273    OPT_ARG_CALLEE_MACRO,
00274    OPT_ARG_PRIVACY,
00275    OPT_ARG_DURATION_STOP,
00276    OPT_ARG_OPERMODE,
00277    OPT_ARG_SCREEN_NOINTRO,
00278    /* note: this entry _MUST_ be the last one in the enum */
00279    OPT_ARG_ARRAY_SIZE,
00280 } dial_exec_option_args;
00281 
00282 AST_APP_OPTIONS(dial_exec_options, {
00283    AST_APP_OPTION_ARG('A', OPT_ANNOUNCE, OPT_ARG_ANNOUNCE),
00284    AST_APP_OPTION('C', OPT_RESETCDR),
00285    AST_APP_OPTION('d', OPT_DTMF_EXIT),
00286    AST_APP_OPTION_ARG('D', OPT_SENDDTMF, OPT_ARG_SENDDTMF),
00287    AST_APP_OPTION('f', OPT_FORCECLID),
00288    AST_APP_OPTION('g', OPT_GO_ON),
00289    AST_APP_OPTION_ARG('G', OPT_GOTO, OPT_ARG_GOTO),
00290    AST_APP_OPTION('h', OPT_CALLEE_HANGUP),
00291    AST_APP_OPTION('H', OPT_CALLER_HANGUP),
00292    AST_APP_OPTION('i', OPT_IGNORE_FORWARDING),
00293    AST_APP_OPTION('j', OPT_PRIORITY_JUMP),
00294    AST_APP_OPTION('k', OPT_CALLEE_PARK),
00295    AST_APP_OPTION('K', OPT_CALLER_PARK),
00296    AST_APP_OPTION_ARG('L', OPT_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT),
00297    AST_APP_OPTION_ARG('m', OPT_MUSICBACK, OPT_ARG_MUSICBACK),
00298    AST_APP_OPTION_ARG('M', OPT_CALLEE_MACRO, OPT_ARG_CALLEE_MACRO),
00299    AST_APP_OPTION_ARG('n', OPT_SCREEN_NOINTRO, OPT_ARG_SCREEN_NOINTRO),
00300    AST_APP_OPTION('N', OPT_SCREEN_NOCLID),
00301    AST_APP_OPTION('o', OPT_ORIGINAL_CLID),
00302    AST_APP_OPTION_ARG('O', OPT_OPERMODE,OPT_ARG_OPERMODE),
00303    AST_APP_OPTION('p', OPT_SCREENING),
00304    AST_APP_OPTION_ARG('P', OPT_PRIVACY, OPT_ARG_PRIVACY),
00305    AST_APP_OPTION('r', OPT_RINGBACK),
00306    AST_APP_OPTION_ARG('S', OPT_DURATION_STOP, OPT_ARG_DURATION_STOP),
00307    AST_APP_OPTION('t', OPT_CALLEE_TRANSFER),
00308    AST_APP_OPTION('T', OPT_CALLER_TRANSFER),
00309    AST_APP_OPTION('w', OPT_CALLEE_MONITOR),
00310    AST_APP_OPTION('W', OPT_CALLER_MONITOR),
00311 });
00312 
00313 #define CAN_EARLY_BRIDGE(flags,chan,peer) (!ast_test_flag(flags, OPT_CALLEE_HANGUP | \
00314    OPT_CALLER_HANGUP | OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER | \
00315    OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR | OPT_CALLEE_PARK |  \
00316    OPT_CALLER_PARK | OPT_ANNOUNCE | OPT_CALLEE_MACRO) && \
00317    !chan->audiohooks && !peer->audiohooks)
00318 
00319 /* We define a custom "local user" structure because we
00320    use it not only for keeping track of what is in use but
00321    also for keeping track of who we're dialing. */
00322 
00323 struct dial_localuser {
00324    struct ast_channel *chan;
00325    unsigned int flags;
00326    struct dial_localuser *next;
00327 };
00328 
00329 
00330 static void hanguptree(struct dial_localuser *outgoing, struct ast_channel *exception)
00331 {
00332    /* Hang up a tree of stuff */
00333    struct dial_localuser *oo;
00334    while (outgoing) {
00335       /* Hangup any existing lines we have open */
00336       if (outgoing->chan && (outgoing->chan != exception))
00337          ast_hangup(outgoing->chan);
00338       oo = outgoing;
00339       outgoing=outgoing->next;
00340       free(oo);
00341    }
00342 }
00343 
00344 #define AST_MAX_WATCHERS 256
00345 
00346 #define HANDLE_CAUSE(cause, chan) do { \
00347    switch(cause) { \
00348    case AST_CAUSE_BUSY: \
00349       if (chan->cdr) \
00350          ast_cdr_busy(chan->cdr); \
00351       numbusy++; \
00352       break; \
00353    case AST_CAUSE_CONGESTION: \
00354       if (chan->cdr) \
00355          ast_cdr_failed(chan->cdr); \
00356       numcongestion++; \
00357       break; \
00358    case AST_CAUSE_NO_ROUTE_DESTINATION: \
00359    case AST_CAUSE_UNREGISTERED: \
00360       if (chan->cdr) \
00361          ast_cdr_failed(chan->cdr); \
00362       numnochan++; \
00363       break; \
00364    case AST_CAUSE_NO_ANSWER: \
00365       if (chan->cdr) \
00366          ast_cdr_noanswer(chan->cdr); \
00367       break; \
00368    case AST_CAUSE_NORMAL_CLEARING: \
00369       break; \
00370    default: \
00371       numnochan++; \
00372       break; \
00373    } \
00374 } while (0)
00375 
00376 
00377 static int onedigit_goto(struct ast_channel *chan, const char *context, char exten, int pri) 
00378 {
00379    char rexten[2] = { exten, '\0' };
00380 
00381    if (context) {
00382       if (!ast_goto_if_exists(chan, context, rexten, pri))
00383          return 1;
00384    } else {
00385       if (!ast_goto_if_exists(chan, chan->context, rexten, pri))
00386          return 1;
00387       else if (!ast_strlen_zero(chan->macrocontext)) {
00388          if (!ast_goto_if_exists(chan, chan->macrocontext, rexten, pri))
00389             return 1;
00390       }
00391    }
00392    return 0;
00393 }
00394 
00395 static int detect_disconnect(struct ast_channel *chan, char code, char *featurecode, int len);
00396 
00397 static const char *get_cid_name(char *name, int namelen, struct ast_channel *chan)
00398 {
00399    const char *context = S_OR(chan->macrocontext, chan->context);
00400    const char *exten = S_OR(chan->macroexten, chan->exten);
00401 
00402    return ast_get_hint(NULL, 0, name, namelen, chan, context, exten) ? name : "";
00403 }
00404 
00405 static void senddialevent(struct ast_channel *src, struct ast_channel *dst)
00406 {
00407    /* XXX do we need also CallerIDnum ? */
00408    manager_event(EVENT_FLAG_CALL, "Dial", 
00409             "Source: %s\r\n"
00410             "Destination: %s\r\n"
00411             "CallerID: %s\r\n"
00412             "CallerIDName: %s\r\n"
00413             "SrcUniqueID: %s\r\n"
00414             "DestUniqueID: %s\r\n",
00415             src->name, dst->name, S_OR(src->cid.cid_num, "<unknown>"),
00416             S_OR(src->cid.cid_name, "<unknown>"), src->uniqueid,
00417             dst->uniqueid);
00418 }
00419 
00420 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)
00421 {
00422    int numbusy = busystart;
00423    int numcongestion = congestionstart;
00424    int numnochan = nochanstart;
00425    int prestart = busystart + congestionstart + nochanstart;
00426    int orig = *to;
00427    struct ast_channel *peer = NULL;
00428    /* single is set if only one destination is enabled */
00429    int single = outgoing && !outgoing->next && !ast_test_flag(outgoing, OPT_MUSICBACK | OPT_RINGBACK);
00430 
00431    char featurecode[FEATURE_MAX_LEN + 1] = { 0, };
00432 
00433    if (single) {
00434       /* Turn off hold music, etc */
00435       ast_deactivate_generator(in);
00436       /* If we are calling a single channel, make them compatible for in-band tone purpose */
00437       ast_channel_make_compatible(outgoing->chan, in);
00438    }
00439    
00440    
00441    while (*to && !peer) {
00442       struct dial_localuser *o;
00443       int pos = 0;   /* how many channels do we handle */
00444       int numlines = prestart;
00445       struct ast_channel *winner;
00446       struct ast_channel *watchers[AST_MAX_WATCHERS];
00447 
00448       watchers[pos++] = in;
00449       for (o = outgoing; o; o = o->next) {
00450          /* Keep track of important channels */
00451          if (ast_test_flag(o, DIAL_STILLGOING) && o->chan)
00452             watchers[pos++] = o->chan;
00453          numlines++;
00454       }
00455       if (pos == 1) {   /* only the input channel is available */
00456          if (numlines == (numbusy + numcongestion + numnochan)) {
00457             if (option_verbose > 2)
00458                ast_verbose( VERBOSE_PREFIX_2 "Everyone is busy/congested at this time (%d:%d/%d/%d)\n", numlines, numbusy, numcongestion, numnochan);
00459             if (numbusy)
00460                strcpy(status, "BUSY"); 
00461             else if (numcongestion)
00462                strcpy(status, "CONGESTION");
00463             else if (numnochan)
00464                strcpy(status, "CHANUNAVAIL");
00465             if (ast_opt_priority_jumping || priority_jump)
00466                ast_goto_if_exists(in, in->context, in->exten, in->priority + 101);
00467          } else {
00468             if (option_verbose > 2)
00469                ast_verbose(VERBOSE_PREFIX_3 "No one is available to answer at this time (%d:%d/%d/%d)\n", numlines, numbusy, numcongestion, numnochan);
00470          }
00471          *to = 0;
00472          return NULL;
00473       }
00474       winner = ast_waitfor_n(watchers, pos, to);
00475       for (o = outgoing; o; o = o->next) {
00476          struct ast_frame *f;
00477          struct ast_channel *c = o->chan;
00478 
00479          if (c == NULL)
00480             continue;
00481          if (ast_test_flag(o, DIAL_STILLGOING) && c->_state == AST_STATE_UP) {
00482             if (!peer) {
00483                if (option_verbose > 2)
00484                   ast_verbose(VERBOSE_PREFIX_3 "%s answered %s\n", c->name, in->name);
00485                peer = c;
00486                ast_copy_flags(peerflags, o,
00487                          OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
00488                          OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
00489                          OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
00490                          OPT_CALLEE_PARK | OPT_CALLER_PARK |
00491                          DIAL_NOFORWARDHTML);
00492                ast_copy_string(c->dialcontext, "", sizeof(c->dialcontext));
00493                ast_copy_string(c->exten, "", sizeof(c->exten));
00494             }
00495             continue;
00496          }
00497          if (c != winner)
00498             continue;
00499          if (!ast_strlen_zero(c->call_forward)) {
00500             char tmpchan[256];
00501             char *stuff;
00502             char *tech;
00503             int cause;
00504 
00505             ast_copy_string(tmpchan, c->call_forward, sizeof(tmpchan));
00506             if ((stuff = strchr(tmpchan, '/'))) {
00507                *stuff++ = '\0';
00508                tech = tmpchan;
00509             } else {
00510                const char *forward_context = pbx_builtin_getvar_helper(c, "FORWARD_CONTEXT");
00511                if (ast_strlen_zero(forward_context)) {
00512                   forward_context = NULL;
00513                }
00514                snprintf(tmpchan, sizeof(tmpchan), "%s@%s", c->call_forward, forward_context ? forward_context : c->context);
00515                stuff = tmpchan;
00516                tech = "Local";
00517             }
00518             /* Before processing channel, go ahead and check for forwarding */
00519             if (option_verbose > 2)
00520                ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, c->name);
00521             /* If we have been told to ignore forwards, just set this channel to null and continue processing extensions normally */
00522             if (ast_test_flag(peerflags, OPT_IGNORE_FORWARDING)) {
00523                if (option_verbose > 2)
00524                   ast_verbose(VERBOSE_PREFIX_3 "Forwarding %s to '%s/%s' prevented.\n", in->name, tech, stuff);
00525                c = o->chan = NULL;
00526                cause = AST_CAUSE_BUSY;
00527             } else {
00528                /* Setup parameters */
00529                if ((c = o->chan = ast_request(tech, in->nativeformats, stuff, &cause))) {
00530                   if (single)
00531                      ast_channel_make_compatible(o->chan, in);
00532                   ast_channel_inherit_variables(in, o->chan);
00533                   ast_channel_datastore_inherit(in, o->chan);
00534                } else
00535                   ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
00536             }
00537             if (!c) {
00538                ast_clear_flag(o, DIAL_STILLGOING); 
00539                HANDLE_CAUSE(cause, in);
00540             } else {
00541                if (CAN_EARLY_BRIDGE(peerflags, c, in)) {
00542                   ast_rtp_make_compatible(c, in, single);
00543                }
00544                if (c->cid.cid_num)
00545                   free(c->cid.cid_num);
00546                c->cid.cid_num = NULL;
00547                if (c->cid.cid_name)
00548                   free(c->cid.cid_name);
00549                c->cid.cid_name = NULL;
00550 
00551                if (ast_test_flag(o, OPT_FORCECLID)) {
00552                   c->cid.cid_num = ast_strdup(S_OR(in->macroexten, in->exten));
00553                   ast_string_field_set(c, accountcode, winner->accountcode);
00554                   c->cdrflags = winner->cdrflags;
00555                } else {
00556                   c->cid.cid_num = ast_strdup(in->cid.cid_num);
00557                   c->cid.cid_name = ast_strdup(in->cid.cid_name);
00558                   ast_string_field_set(c, accountcode, in->accountcode);
00559                   c->cdrflags = in->cdrflags;
00560                }
00561 
00562                if (in->cid.cid_ani) {
00563                   if (c->cid.cid_ani)
00564                      free(c->cid.cid_ani);
00565                   c->cid.cid_ani = ast_strdup(in->cid.cid_ani);
00566                }
00567                if (c->cid.cid_rdnis) 
00568                   free(c->cid.cid_rdnis);
00569                c->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten));
00570                if (ast_call(c, tmpchan, 0)) {
00571                   ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
00572                   ast_clear_flag(o, DIAL_STILLGOING); 
00573                   ast_hangup(c);
00574                   c = o->chan = NULL;
00575                   numnochan++;
00576                } else {
00577                   senddialevent(in, c);
00578                   /* After calling, set callerid to extension */
00579                   if (!ast_test_flag(peerflags, OPT_ORIGINAL_CLID)) {
00580                      char cidname[AST_MAX_EXTENSION] = "";
00581                      ast_set_callerid(c, S_OR(in->macroexten, in->exten), get_cid_name(cidname, sizeof(cidname), in), NULL);
00582                   }
00583                }
00584                if (single) {
00585                   ast_indicate(in, -1);
00586                }
00587             }
00588             /* Hangup the original channel now, in case we needed it */
00589             ast_hangup(winner);
00590             continue;
00591          }
00592          f = ast_read(winner);
00593          if (!f) {
00594             in->hangupcause = c->hangupcause;
00595             ast_hangup(c);
00596             c = o->chan = NULL;
00597             ast_clear_flag(o, DIAL_STILLGOING);
00598             HANDLE_CAUSE(in->hangupcause, in);
00599             continue;
00600          }
00601          if (f->frametype == AST_FRAME_CONTROL) {
00602             switch(f->subclass) {
00603             case AST_CONTROL_ANSWER:
00604                /* This is our guy if someone answered. */
00605                if (!peer) {
00606                   if (option_verbose > 2)
00607                      ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", c->name, in->name);
00608                   peer = c;
00609                   if (peer->cdr) {
00610                      peer->cdr->answer = ast_tvnow();
00611                      peer->cdr->disposition = AST_CDR_ANSWERED;
00612                   }
00613                   ast_copy_flags(peerflags, o,
00614                             OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
00615                             OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
00616                             OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
00617                             OPT_CALLEE_PARK | OPT_CALLER_PARK |
00618                             DIAL_NOFORWARDHTML);
00619                   ast_copy_string(c->dialcontext, "", sizeof(c->dialcontext));
00620                   ast_copy_string(c->exten, "", sizeof(c->exten));
00621                   /* Setup RTP early bridge if appropriate */
00622                   if (CAN_EARLY_BRIDGE(peerflags, in, peer))
00623                      ast_rtp_early_bridge(in, peer);
00624                }
00625                /* If call has been answered, then the eventual hangup is likely to be normal hangup */
00626                in->hangupcause = AST_CAUSE_NORMAL_CLEARING;
00627                c->hangupcause = AST_CAUSE_NORMAL_CLEARING;
00628                break;
00629             case AST_CONTROL_BUSY:
00630                if (option_verbose > 2)
00631                   ast_verbose(VERBOSE_PREFIX_3 "%s is busy\n", c->name);
00632                in->hangupcause = c->hangupcause;
00633                ast_hangup(c);
00634                c = o->chan = NULL;
00635                ast_clear_flag(o, DIAL_STILLGOING); 
00636                HANDLE_CAUSE(AST_CAUSE_BUSY, in);
00637                break;
00638             case AST_CONTROL_CONGESTION:
00639                if (option_verbose > 2)
00640                   ast_verbose(VERBOSE_PREFIX_3 "%s is circuit-busy\n", c->name);
00641                in->hangupcause = c->hangupcause;
00642                ast_hangup(c);
00643                c = o->chan = NULL;
00644                ast_clear_flag(o, DIAL_STILLGOING);
00645                HANDLE_CAUSE(AST_CAUSE_CONGESTION, in);
00646                break;
00647             case AST_CONTROL_RINGING:
00648                if (option_verbose > 2)
00649                   ast_verbose(VERBOSE_PREFIX_3 "%s is ringing\n", c->name);
00650                /* Setup early media if appropriate */
00651                if (single && CAN_EARLY_BRIDGE(peerflags, in, c))
00652                   ast_rtp_early_bridge(in, c);
00653                if (!(*sentringing) && !ast_test_flag(outgoing, OPT_MUSICBACK)) {
00654                   ast_indicate(in, AST_CONTROL_RINGING);
00655                   (*sentringing)++;
00656                }
00657                break;
00658             case AST_CONTROL_PROGRESS:
00659                if (option_verbose > 2)
00660                   ast_verbose (VERBOSE_PREFIX_3 "%s is making progress passing it to %s\n", c->name, in->name);
00661                /* Setup early media if appropriate */
00662                if (single && CAN_EARLY_BRIDGE(peerflags, in, c))
00663                   ast_rtp_early_bridge(in, c);
00664                if (!ast_test_flag(outgoing, OPT_RINGBACK)) {
00665                      if (single || (!single && !(*sentringing))) {
00666                      /* want progress to go through if it's a single legged call or it's a
00667                       * branched call and ringing has not been sent */
00668                         ast_indicate(in, AST_CONTROL_PROGRESS);
00669                      }
00670                }
00671                break;
00672             case AST_CONTROL_VIDUPDATE:
00673                if (option_verbose > 2)
00674                   ast_verbose (VERBOSE_PREFIX_3 "%s requested a video update, passing it to %s\n", c->name, in->name);
00675                ast_indicate(in, AST_CONTROL_VIDUPDATE);
00676                break;
00677             case AST_CONTROL_SRCUPDATE:
00678                if (option_verbose > 2)
00679                   ast_verbose (VERBOSE_PREFIX_3 "%s requested a source update, passing it to %s\n", c->name, in->name);
00680                ast_indicate(in, AST_CONTROL_SRCUPDATE);
00681                break;
00682             case AST_CONTROL_PROCEEDING:
00683                if (option_verbose > 2)
00684                   ast_verbose (VERBOSE_PREFIX_3 "%s is proceeding passing it to %s\n", c->name, in->name);
00685                if (single && CAN_EARLY_BRIDGE(peerflags, in, c))
00686                   ast_rtp_early_bridge(in, c);
00687                if (!ast_test_flag(outgoing, OPT_RINGBACK))
00688                   ast_indicate(in, AST_CONTROL_PROCEEDING);
00689                break;
00690             case AST_CONTROL_HOLD:
00691                if (option_verbose > 2)
00692                   ast_verbose(VERBOSE_PREFIX_3 "Call on %s placed on hold\n", c->name);
00693                ast_indicate(in, AST_CONTROL_HOLD);
00694                break;
00695             case AST_CONTROL_UNHOLD:
00696                if (option_verbose > 2)
00697                   ast_verbose(VERBOSE_PREFIX_3 "Call on %s left from hold\n", c->name);
00698                ast_indicate(in, AST_CONTROL_UNHOLD);
00699                break;
00700             case AST_CONTROL_OFFHOOK:
00701             case AST_CONTROL_FLASH:
00702                /* Ignore going off hook and flash */
00703                break;
00704             case -1:
00705                if (!ast_test_flag(outgoing, OPT_RINGBACK | OPT_MUSICBACK)) {
00706                   if (option_verbose > 2)
00707                      ast_verbose(VERBOSE_PREFIX_3 "%s stopped sounds\n", c->name);
00708                   ast_indicate(in, -1);
00709                   (*sentringing) = 0;
00710                }
00711                break;
00712             default:
00713                if (option_debug)
00714                   ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
00715             }
00716          } else if (single) {
00717             /* XXX are we sure the logic is correct ? or we should just switch on f->frametype ? */
00718             if (f->frametype == AST_FRAME_VOICE && !ast_test_flag(outgoing, OPT_RINGBACK|OPT_MUSICBACK)) {
00719                if (ast_write(in, f)) 
00720                   ast_log(LOG_WARNING, "Unable to forward voice frame\n");
00721             } else if (f->frametype == AST_FRAME_IMAGE && !ast_test_flag(outgoing, OPT_RINGBACK|OPT_MUSICBACK)) {
00722                if (ast_write(in, f))
00723                   ast_log(LOG_WARNING, "Unable to forward image\n");
00724             } else if (f->frametype == AST_FRAME_TEXT && !ast_test_flag(outgoing, OPT_RINGBACK|OPT_MUSICBACK)) {
00725                if (ast_write(in, f))
00726                   ast_log(LOG_WARNING, "Unable to send text\n");
00727             } else if (f->frametype == AST_FRAME_HTML && !ast_test_flag(outgoing, DIAL_NOFORWARDHTML)) {
00728                if (ast_channel_sendhtml(in, f->subclass, f->data, f->datalen) == -1)
00729                   ast_log(LOG_WARNING, "Unable to send URL\n");
00730             }
00731          }
00732          ast_frfree(f);
00733       } /* end for */
00734       if (winner == in) {
00735          struct ast_frame *f = ast_read(in);
00736 #if 0
00737          if (f && (f->frametype != AST_FRAME_VOICE))
00738             printf("Frame type: %d, %d\n", f->frametype, f->subclass);
00739          else if (!f || (f->frametype != AST_FRAME_VOICE))
00740             printf("Hangup received on %s\n", in->name);
00741 #endif
00742          if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
00743             /* Got hung up */
00744             *to = -1;
00745             ast_cdr_noanswer(in->cdr);
00746             strcpy(status, "CANCEL");
00747             if (f)
00748                ast_frfree(f);
00749             return NULL;
00750          }
00751 
00752          if (f && (f->frametype == AST_FRAME_DTMF)) {
00753             if (ast_test_flag(peerflags, OPT_DTMF_EXIT)) {
00754                const char *context = pbx_builtin_getvar_helper(in, "EXITCONTEXT");
00755                if (onedigit_goto(in, context, (char) f->subclass, 1)) {
00756                   if (option_verbose > 2)
00757                      ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
00758                   *to=0;
00759                   ast_cdr_noanswer(in->cdr);
00760                   *result = f->subclass;
00761                   strcpy(status, "CANCEL");
00762                   ast_frfree(f);
00763                   return NULL;
00764                }
00765             }
00766 
00767             if (ast_test_flag(peerflags, OPT_CALLER_HANGUP) &&
00768                detect_disconnect(in, f->subclass, featurecode, sizeof(featurecode))) {
00769                if (option_verbose > 2)
00770                   ast_verbose(VERBOSE_PREFIX_3 "User requested call disconnect.\n");
00771                *to=0;
00772                ast_cdr_noanswer(in->cdr);
00773                strcpy(status, "CANCEL");
00774                ast_frfree(f);
00775                return NULL;
00776             }
00777          }
00778 
00779          /* Forward HTML stuff */
00780          if (single && f && (f->frametype == AST_FRAME_HTML) && !ast_test_flag(outgoing, DIAL_NOFORWARDHTML)) 
00781             if(ast_channel_sendhtml(outgoing->chan, f->subclass, f->data, f->datalen) == -1)
00782                ast_log(LOG_WARNING, "Unable to send URL\n");
00783          
00784 
00785          if (single && ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_DTMF_BEGIN) || (f->frametype == AST_FRAME_DTMF_END)))  {
00786             if (ast_write(outgoing->chan, f))
00787                ast_log(LOG_WARNING, "Unable to forward voice or dtmf\n");
00788          }
00789          if (single && (f->frametype == AST_FRAME_CONTROL) && 
00790             ((f->subclass == AST_CONTROL_HOLD) || 
00791              (f->subclass == AST_CONTROL_UNHOLD) || 
00792              (f->subclass == AST_CONTROL_VIDUPDATE) ||
00793              (f->subclass == AST_CONTROL_SRCUPDATE))) {
00794             if (option_verbose > 2)
00795                ast_verbose(VERBOSE_PREFIX_3 "%s requested special control %d, passing it to %s\n", in->name, f->subclass, outgoing->chan->name);
00796             ast_indicate_data(outgoing->chan, f->subclass, f->data, f->datalen);
00797          }
00798          ast_frfree(f);
00799       }
00800       if (!*to && (option_verbose > 2))
00801          ast_verbose(VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
00802       if (!*to || ast_check_hangup(in)) {
00803          ast_cdr_noanswer(in->cdr);
00804       }
00805       
00806    }
00807    
00808    return peer;
00809 }
00810 
00811 static int detect_disconnect(struct ast_channel *chan, char code, char *featurecode, int len)
00812 {
00813    struct ast_flags features = { AST_FEATURE_DISCONNECT }; /* only concerned with disconnect feature */
00814    struct ast_call_feature feature = { 0, };
00815    char *tmp;
00816    int res;
00817 
00818    if ((strlen(featurecode)) < (len - 2)) { 
00819       tmp = &featurecode[strlen(featurecode)];
00820       tmp[0] = code;
00821       tmp[1] = '\0';
00822    } else {
00823       featurecode[0] = 0;
00824       return -1; /* no room in featurecode buffer */
00825    }
00826 
00827    res = ast_feature_detect(chan, &features, featurecode, &feature);
00828 
00829    if (res != FEATURE_RETURN_STOREDIGITS) {
00830       featurecode[0] = '\0';
00831    }
00832    if (feature.feature_mask & AST_FEATURE_DISCONNECT) {
00833       return 1;
00834    }
00835 
00836    return 0;
00837 }
00838 
00839 static void replace_macro_delimiter(char *s)
00840 {
00841    for (; *s; s++)
00842       if (*s == '^')
00843          *s = '|';
00844 }
00845 
00846 
00847 /* returns true if there is a valid privacy reply */
00848 static int valid_priv_reply(struct ast_flags *opts, int res)
00849 {
00850    if (res < '1')
00851       return 0;
00852    if (ast_test_flag(opts, OPT_PRIVACY) && res <= '5')
00853       return 1;
00854    if (ast_test_flag(opts, OPT_SCREENING) && res <= '4')
00855       return 1;
00856    return 0;
00857 }
00858 
00859 static void end_bridge_callback (void *data)
00860 {
00861    char buf[80];
00862    time_t end;
00863    struct ast_channel *chan = data;
00864 
00865    if (!chan->cdr) {
00866       return;
00867    }
00868 
00869    time(&end);
00870 
00871    ast_channel_lock(chan);
00872    if (chan->cdr->answer.tv_sec) {
00873       snprintf(buf, sizeof(buf), "%ld", end - chan->cdr->answer.tv_sec);
00874       pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf);
00875    }
00876 
00877    if (chan->cdr->start.tv_sec) {
00878       snprintf(buf, sizeof(buf), "%ld", end - chan->cdr->start.tv_sec);
00879       pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf);
00880    }
00881    ast_channel_unlock(chan);
00882 }
00883 
00884 static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator) {
00885    bconfig->end_bridge_callback_data = originator;
00886 }
00887 
00888 static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags *peerflags, int *continue_exec)
00889 {
00890    int res = -1;
00891    struct ast_module_user *u;
00892    char *rest, *cur;
00893    struct dial_localuser *outgoing = NULL;
00894    struct ast_channel *peer;
00895    int to;
00896    int numbusy = 0;
00897    int numcongestion = 0;
00898    int numnochan = 0;
00899    int cause;
00900    char numsubst[256];
00901    char cidname[AST_MAX_EXTENSION] = "";
00902    int privdb_val = 0;
00903    int calldurationlimit = -1;
00904    long timelimit = 0;
00905    long play_warning = 0;
00906    long warning_freq = 0;
00907    const char *warning_sound = NULL;
00908    const char *end_sound = NULL;
00909    const char *start_sound = NULL;
00910    char *dtmfcalled = NULL, *dtmfcalling = NULL;
00911    char status[256] = "INVALIDARGS";
00912    int play_to_caller = 0, play_to_callee = 0;
00913    int sentringing = 0, moh = 0;
00914    const char *outbound_group = NULL;
00915    int result = 0;
00916    time_t start_time;
00917    char privintro[1024];
00918    char privcid[256];
00919    char *parse;
00920    int opermode = 0;
00921    int delprivintro = 0;
00922    AST_DECLARE_APP_ARGS(args,
00923               AST_APP_ARG(peers);
00924               AST_APP_ARG(timeout);
00925               AST_APP_ARG(options);
00926               AST_APP_ARG(url);
00927    );
00928    struct ast_flags opts = { 0, };
00929    char *opt_args[OPT_ARG_ARRAY_SIZE];
00930    struct ast_datastore *datastore = NULL;
00931    int fulldial = 0, num_dialed = 0;
00932 
00933    if (ast_strlen_zero(data)) {
00934       ast_log(LOG_WARNING, "Dial requires an argument (technology/number)\n");
00935       pbx_builtin_setvar_helper(chan, "DIALSTATUS", status);
00936       return -1;
00937    }
00938 
00939    /* Reset all DIAL variables back to blank, to prevent confusion (in case we don't reset all of them). */
00940    pbx_builtin_setvar_helper(chan, "DIALSTATUS", "");
00941    pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", "");
00942    pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", "");
00943    pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", "");
00944    pbx_builtin_setvar_helper(chan, "DIALEDTIME", "");
00945 
00946    u = ast_module_user_add(chan);
00947 
00948    parse = ast_strdupa(data);
00949    
00950    AST_STANDARD_APP_ARGS(args, parse);
00951 
00952    if (!ast_strlen_zero(args.options) &&
00953          ast_app_parse_options(dial_exec_options, &opts, opt_args, args.options)) {
00954       pbx_builtin_setvar_helper(chan, "DIALSTATUS", status);
00955       goto done;
00956    }
00957 
00958    if (ast_strlen_zero(args.peers)) {
00959       ast_log(LOG_WARNING, "Dial requires an argument (technology/number)\n");
00960       pbx_builtin_setvar_helper(chan, "DIALSTATUS", status);
00961       goto done;
00962    }
00963 
00964    if (ast_test_flag(&opts, OPT_SCREEN_NOINTRO)) {
00965       if (!ast_strlen_zero(opt_args[OPT_ARG_SCREEN_NOINTRO])) {
00966          int mode = atoi(opt_args[OPT_ARG_SCREEN_NOINTRO]);
00967          if (mode < 0 || mode > 1) {
00968             ast_log(LOG_WARNING, "Unknown argument %d specified to n option, ignoring\n", mode);
00969          } else {
00970             delprivintro = mode;
00971          }
00972       }
00973    }
00974 
00975    if (ast_test_flag(&opts, OPT_OPERMODE)) {
00976       if (ast_strlen_zero(opt_args[OPT_ARG_OPERMODE]))
00977          opermode = 1;
00978       else opermode = atoi(opt_args[OPT_ARG_OPERMODE]);
00979       if (option_verbose > 2)
00980          ast_verbose(VERBOSE_PREFIX_3 "Setting operator services mode to %d.\n", opermode);
00981    }
00982    
00983    if (ast_test_flag(&opts, OPT_DURATION_STOP) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_STOP])) {
00984       calldurationlimit = atoi(opt_args[OPT_ARG_DURATION_STOP]);
00985       if (!calldurationlimit) {
00986          ast_log(LOG_WARNING, "Dial does not accept S(%s), hanging up.\n", opt_args[OPT_ARG_DURATION_STOP]);
00987          pbx_builtin_setvar_helper(chan, "DIALSTATUS", status);
00988          goto done;
00989       }
00990       if (option_verbose > 2)
00991          ast_verbose(VERBOSE_PREFIX_3 "Setting call duration limit to %d seconds.\n", calldurationlimit);
00992    }
00993 
00994    if (ast_test_flag(&opts, OPT_SENDDTMF) && !ast_strlen_zero(opt_args[OPT_ARG_SENDDTMF])) {
00995       dtmfcalling = opt_args[OPT_ARG_SENDDTMF];
00996       dtmfcalled = strsep(&dtmfcalling, ":");
00997    }
00998 
00999    if (ast_test_flag(&opts, OPT_DURATION_LIMIT) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])) {
01000       char *limit_str, *warning_str, *warnfreq_str;
01001       const char *var;
01002 
01003       warnfreq_str = opt_args[OPT_ARG_DURATION_LIMIT];
01004       limit_str = strsep(&warnfreq_str, ":");
01005       warning_str = strsep(&warnfreq_str, ":");
01006 
01007       timelimit = atol(limit_str);
01008       if (warning_str)
01009          play_warning = atol(warning_str);
01010       if (warnfreq_str)
01011          warning_freq = atol(warnfreq_str);
01012 
01013       if (!timelimit) {
01014          ast_log(LOG_WARNING, "Dial does not accept L(%s), hanging up.\n", limit_str);
01015          goto done;
01016       } else if (play_warning > timelimit) {
01017          /* If the first warning is requested _after_ the entire call would end,
01018             and no warning frequency is requested, then turn off the warning. If
01019             a warning frequency is requested, reduce the 'first warning' time by
01020             that frequency until it falls within the call's total time limit.
01021          */
01022 
01023          if (!warning_freq) {
01024             play_warning = 0;
01025          } else {
01026             /* XXX fix this!! */
01027             while (play_warning > timelimit)
01028                play_warning -= warning_freq;
01029             if (play_warning < 1)
01030                play_warning = warning_freq = 0;
01031          }
01032       }
01033 
01034       var = pbx_builtin_getvar_helper(chan,"LIMIT_PLAYAUDIO_CALLER");
01035       play_to_caller = var ? ast_true(var) : 1;
01036       
01037       var = pbx_builtin_getvar_helper(chan,"LIMIT_PLAYAUDIO_CALLEE");
01038       play_to_callee = var ? ast_true(var) : 0;
01039       
01040       if (!play_to_caller && !play_to_callee)
01041          play_to_caller = 1;
01042       
01043       var = pbx_builtin_getvar_helper(chan,"LIMIT_WARNING_FILE");
01044       warning_sound = S_OR(var, "timeleft");
01045       
01046       var = pbx_builtin_getvar_helper(chan,"LIMIT_TIMEOUT_FILE");
01047       end_sound = S_OR(var, "");
01048       
01049       var = pbx_builtin_getvar_helper(chan,"LIMIT_CONNECT_FILE");
01050       start_sound = S_OR(var, "");
01051 
01052       /* undo effect of S(x) in case they are both used */
01053       calldurationlimit = -1;
01054       /* more efficient to do it like S(x) does since no advanced opts */
01055       if (!play_warning && !start_sound && !end_sound && timelimit) {
01056          calldurationlimit = timelimit / 1000;
01057          if (option_verbose > 2)
01058             ast_verbose(VERBOSE_PREFIX_3 "Setting call duration limit to %d seconds.\n", calldurationlimit);
01059          timelimit = play_to_caller = play_to_callee = play_warning = warning_freq = 0;
01060       } else if (option_verbose > 2) {
01061          ast_verbose(VERBOSE_PREFIX_3 "Limit Data for this call:\n");
01062          ast_verbose(VERBOSE_PREFIX_4 "timelimit      = %ld\n", timelimit);
01063          ast_verbose(VERBOSE_PREFIX_4 "play_warning   = %ld\n", play_warning);
01064          ast_verbose(VERBOSE_PREFIX_4 "play_to_caller = %s\n", play_to_caller ? "yes" : "no");
01065          ast_verbose(VERBOSE_PREFIX_4 "play_to_callee = %s\n", play_to_callee ? "yes" : "no");
01066          ast_verbose(VERBOSE_PREFIX_4 "warning_freq   = %ld\n", warning_freq);
01067          ast_verbose(VERBOSE_PREFIX_4 "start_sound    = %s\n", start_sound);
01068          ast_verbose(VERBOSE_PREFIX_4 "warning_sound  = %s\n", warning_sound);
01069          ast_verbose(VERBOSE_PREFIX_4 "end_sound      = %s\n", end_sound);
01070       }
01071    }
01072 
01073    if (ast_test_flag(&opts, OPT_RESETCDR) && chan->cdr)
01074       ast_cdr_reset(chan->cdr, NULL);
01075    if (ast_test_flag(&opts, OPT_PRIVACY) && ast_strlen_zero(opt_args[OPT_ARG_PRIVACY]))
01076       opt_args[OPT_ARG_PRIVACY] = ast_strdupa(chan->exten);
01077    if (ast_test_flag(&opts, OPT_PRIVACY) || ast_test_flag(&opts, OPT_SCREENING)) {
01078       char callerid[60];
01079       char *l = chan->cid.cid_num;  /* XXX watch out, we are overwriting it */
01080       if (!ast_strlen_zero(l)) {
01081          ast_shrink_phone_number(l);
01082          if( ast_test_flag(&opts, OPT_PRIVACY) ) {
01083             if (option_verbose > 2)
01084                ast_verbose(VERBOSE_PREFIX_3  "Privacy DB is '%s', clid is '%s'\n",
01085                        opt_args[OPT_ARG_PRIVACY], l);
01086             privdb_val = ast_privacy_check(opt_args[OPT_ARG_PRIVACY], l);
01087          }
01088          else {
01089             if (option_verbose > 2)
01090                ast_verbose(VERBOSE_PREFIX_3  "Privacy Screening, clid is '%s'\n", l);
01091             privdb_val = AST_PRIVACY_UNKNOWN;
01092          }
01093       } else {
01094          char *tnam, *tn2;
01095 
01096          tnam = ast_strdupa(chan->name);
01097          /* clean the channel name so slashes don't try to end up in disk file name */
01098          for(tn2 = tnam; *tn2; tn2++) {
01099             if( *tn2=='/')
01100                *tn2 = '=';  /* any other chars to be afraid of? */
01101          }
01102          if (option_verbose > 2)
01103             ast_verbose(VERBOSE_PREFIX_3  "Privacy-- callerid is empty\n");
01104 
01105          snprintf(callerid, sizeof(callerid), "NOCALLERID_%s%s", chan->exten, tnam);
01106          l = callerid;
01107          privdb_val = AST_PRIVACY_UNKNOWN;
01108       }
01109       
01110       ast_copy_string(privcid,l,sizeof(privcid));
01111 
01112       if( strncmp(privcid,"NOCALLERID",10) != 0 && ast_test_flag(&opts, OPT_SCREEN_NOCLID) ) { /* if callerid is set, and ast_test_flag(&opts, OPT_SCREEN_NOCLID) is set also */  
01113          if (option_verbose > 2)
01114             ast_verbose( VERBOSE_PREFIX_3  "CallerID set (%s); N option set; Screening should be off\n", privcid);
01115          privdb_val = AST_PRIVACY_ALLOW;
01116       }
01117       else if(ast_test_flag(&opts, OPT_SCREEN_NOCLID) && strncmp(privcid,"NOCALLERID",10) == 0 ) {
01118          if (option_verbose > 2)
01119             ast_verbose( VERBOSE_PREFIX_3  "CallerID blank; N option set; Screening should happen; dbval is %d\n", privdb_val);
01120       }
01121       
01122       if(privdb_val == AST_PRIVACY_DENY ) {
01123          ast_copy_string(status, "NOANSWER", sizeof(status));
01124          if (option_verbose > 2)
01125             ast_verbose( VERBOSE_PREFIX_3  "Privacy DB reports PRIVACY_DENY for this callerid. Dial reports unavailable\n");
01126          res=0;
01127          goto out;
01128       }
01129       else if(privdb_val == AST_PRIVACY_KILL ) {
01130          ast_copy_string(status, "DONTCALL", sizeof(status));
01131          if (ast_opt_priority_jumping || ast_test_flag(&opts, OPT_PRIORITY_JUMP)) {
01132             ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 201);
01133          }
01134          res = 0;
01135          goto out; /* Is this right? */
01136       }
01137       else if(privdb_val == AST_PRIVACY_TORTURE ) {
01138          ast_copy_string(status, "TORTURE", sizeof(status));
01139          if (ast_opt_priority_jumping || ast_test_flag(&opts, OPT_PRIORITY_JUMP)) {
01140             ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 301);
01141          }
01142          res = 0;
01143          goto out; /* is this right??? */
01144       }
01145       else if(privdb_val == AST_PRIVACY_UNKNOWN ) {
01146          /* Get the user's intro, store it in priv-callerintros/$CID, 
01147             unless it is already there-- this should be done before the 
01148             call is actually dialed  */
01149 
01150          /* make sure the priv-callerintros dir actually exists */
01151          snprintf(privintro, sizeof(privintro), "%s/sounds/priv-callerintros", ast_config_AST_DATA_DIR);
01152          if (mkdir(privintro, 0755) && errno != EEXIST) {
01153             ast_log(LOG_WARNING, "privacy: can't create directory priv-callerintros: %s\n", strerror(errno));
01154             res = -1;
01155             goto out;
01156          }
01157 
01158          snprintf(privintro,sizeof(privintro), "priv-callerintros/%s", privcid);
01159          if( ast_fileexists(privintro,NULL,NULL ) > 0 && strncmp(privcid,"NOCALLERID",10) != 0) {
01160             /* the DELUX version of this code would allow this caller the
01161                option to hear and retape their previously recorded intro.
01162             */
01163          }
01164          else {
01165             int duration; /* for feedback from play_and_wait */
01166             /* the file doesn't exist yet. Let the caller submit his
01167                vocal intro for posterity */
01168             /* priv-recordintro script:
01169 
01170                "At the tone, please say your name:"
01171 
01172             */
01173             ast_answer(chan);
01174             res = ast_play_and_record(chan, "priv-recordintro", privintro, 4, "gsm", &duration, 128, 2000, 0);  /* NOTE: I've reduced the total time to 4 sec */
01175                               /* don't think we'll need a lock removed, we took care of
01176                                  conflicts by naming the privintro file */
01177             if (res == -1) {
01178                /* Delete the file regardless since they hung up during recording */
01179                delprivintro = 1;
01180                goto out;
01181             }
01182                                 if( !ast_streamfile(chan, "vm-dialout", chan->language) )
01183                                         ast_waitstream(chan, "");
01184          }
01185       }
01186    }
01187 
01188    if (continue_exec)
01189       *continue_exec = 0;
01190    
01191    /* If a channel group has been specified, get it for use when we create peer channels */
01192    if ((outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP_ONCE"))) {
01193       outbound_group = ast_strdupa(outbound_group);
01194       pbx_builtin_setvar_helper(chan, "OUTBOUND_GROUP_ONCE", NULL);
01195    } else {
01196       outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP");
01197    }
01198        
01199    ast_copy_flags(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING | OPT_ANNOUNCE | OPT_CALLEE_MACRO);
01200 
01201    /* loop through the list of dial destinations */
01202    rest = args.peers;
01203    while ((cur = strsep(&rest, "&")) ) {
01204       struct dial_localuser *tmp;
01205       /* Get a technology/[device:]number pair */
01206       char *number = cur;
01207       char *interface = ast_strdupa(number);
01208       char *tech = strsep(&number, "/");
01209       /* find if we already dialed this interface */
01210       struct ast_dialed_interface *di;
01211       AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces;
01212       num_dialed++;
01213       if (!number) {
01214          ast_log(LOG_WARNING, "Dial argument takes format (technology/[device:]number1)\n");
01215          goto out;
01216       }
01217       if (!(tmp = ast_calloc(1, sizeof(*tmp))))
01218          goto out;
01219       if (opts.flags) {
01220          ast_copy_flags(tmp, &opts,
01221                    OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
01222                    OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
01223                    OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
01224                    OPT_CALLEE_PARK | OPT_CALLER_PARK |
01225                    OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID);
01226          ast_set2_flag(tmp, args.url, DIAL_NOFORWARDHTML);  
01227       }
01228       ast_copy_string(numsubst, number, sizeof(numsubst));
01229       /* Request the peer */
01230 
01231       ast_channel_lock(chan);
01232       datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL);
01233       ast_channel_unlock(chan);
01234 
01235       if (datastore)
01236          dialed_interfaces = datastore->data;
01237       else {
01238          if (!(datastore = ast_channel_datastore_alloc(&dialed_interface_info, NULL))) {
01239             ast_log(LOG_WARNING, "Unable to create channel datastore for dialed interfaces. Aborting!\n"); 
01240             free(tmp);
01241             goto out;
01242          }
01243 
01244          datastore->inheritance = DATASTORE_INHERIT_FOREVER;
01245 
01246          if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) {
01247             ast_channel_datastore_free(datastore);
01248             free(tmp);
01249             goto out;
01250          }
01251 
01252          datastore->data = dialed_interfaces;
01253          AST_LIST_HEAD_INIT(dialed_interfaces);
01254 
01255          ast_channel_lock(chan);
01256          ast_channel_datastore_add(chan, datastore);
01257          ast_channel_unlock(chan);
01258       }
01259 
01260       AST_LIST_LOCK(dialed_interfaces);
01261       AST_LIST_TRAVERSE(dialed_interfaces, di, list) {
01262          if (!strcasecmp(di->interface, interface)) {
01263             ast_log(LOG_WARNING, "Skipping dialing interface '%s' again since it has already been dialed\n", 
01264                di->interface);
01265             break;
01266          }
01267       }
01268       AST_LIST_UNLOCK(dialed_interfaces);
01269 
01270       if (di) {
01271          fulldial++;
01272          free(tmp);
01273          continue;
01274       }
01275 
01276       /* It is always ok to dial a Local interface.  We only keep track of
01277        * which "real" interfaces have been dialed.  The Local channel will
01278        * inherit this list so that if it ends up dialing a real interface,
01279        * it won't call one that has already been called. */
01280       if (strcasecmp(tech, "Local")) {
01281          if (!(di = ast_calloc(1, sizeof(*di) + strlen(interface)))) {
01282             AST_LIST_UNLOCK(dialed_interfaces);
01283             free(tmp);
01284             goto out;
01285          }
01286          strcpy(di->interface, interface);
01287 
01288          AST_LIST_LOCK(dialed_interfaces);
01289          AST_LIST_INSERT_TAIL(dialed_interfaces, di, list);
01290          AST_LIST_UNLOCK(dialed_interfaces);
01291       }
01292 
01293       tmp->chan = ast_request(tech, chan->nativeformats, numsubst, &cause);
01294       if (!tmp->chan) {
01295          /* If we can't, just go on to the next call */
01296          ast_log(LOG_WARNING, "Unable to create channel of type '%s' (cause %d - %s)\n", tech, cause, ast_cause2str(cause));
01297          HANDLE_CAUSE(cause, chan);
01298          if (!rest)  /* we are on the last destination */
01299             chan->hangupcause = cause;
01300          free(tmp);
01301          continue;
01302       }
01303 
01304       pbx_builtin_setvar_helper(tmp->chan, "DIALEDPEERNUMBER", numsubst);
01305 
01306       /* Setup outgoing SDP to match incoming one */
01307       if (CAN_EARLY_BRIDGE(peerflags, chan, tmp->chan)) {
01308          ast_rtp_make_compatible(tmp->chan, chan, !outgoing && !rest);
01309       }
01310 
01311       /* Inherit specially named variables from parent channel */
01312       ast_channel_inherit_variables(chan, tmp->chan);
01313       ast_channel_datastore_inherit(chan, tmp->chan);
01314 
01315       tmp->chan->appl = "AppDial";
01316       tmp->chan->data = "(Outgoing Line)";
01317       tmp->chan->whentohangup = 0;
01318 
01319       if (tmp->chan->cid.cid_num)
01320          free(tmp->chan->cid.cid_num);
01321       tmp->chan->cid.cid_num = ast_strdup(chan->cid.cid_num);
01322 
01323       if (tmp->chan->cid.cid_name)
01324          free(tmp->chan->cid.cid_name);
01325       tmp->chan->cid.cid_name = ast_strdup(chan->cid.cid_name);
01326 
01327       if (tmp->chan->cid.cid_ani)
01328          free(tmp->chan->cid.cid_ani);
01329       tmp->chan->cid.cid_ani = ast_strdup(chan->cid.cid_ani);
01330       
01331       /* Copy language from incoming to outgoing */
01332       ast_string_field_set(tmp->chan, language, chan->language);
01333       ast_string_field_set(tmp->chan, accountcode, chan->accountcode);
01334       tmp->chan->cdrflags = chan->cdrflags;
01335       if (ast_strlen_zero(tmp->chan->musicclass))
01336          ast_string_field_set(tmp->chan, musicclass, chan->musicclass);
01337       /* XXX don't we free previous values ? */
01338       tmp->chan->cid.cid_rdnis = ast_strdup(chan->cid.cid_rdnis);
01339       /* Pass callingpres setting */
01340       tmp->chan->cid.cid_pres = chan->cid.cid_pres;
01341       /* Pass type of number */
01342       tmp->chan->cid.cid_ton = chan->cid.cid_ton;
01343       /* Pass type of tns */
01344       tmp->chan->cid.cid_tns = chan->cid.cid_tns;
01345       /* Presense of ADSI CPE on outgoing channel follows ours */
01346       tmp->chan->adsicpe = chan->adsicpe;
01347       /* Pass the transfer capability */
01348       tmp->chan->transfercapability = chan->transfercapability;
01349 
01350       /* If we have an outbound group, set this peer channel to it */
01351       if (outbound_group)
01352          ast_app_group_set_channel(tmp->chan, outbound_group);
01353 
01354       /* Inherit context and extension */
01355       if (!ast_strlen_zero(chan->macrocontext))
01356          ast_copy_string(tmp->chan->dialcontext, chan->macrocontext, sizeof(tmp->chan->dialcontext));
01357       else
01358          ast_copy_string(tmp->chan->dialcontext, chan->context, sizeof(tmp->chan->dialcontext));
01359       if (!ast_strlen_zero(chan->macroexten))
01360          ast_copy_string(tmp->chan->exten, chan->macroexten, sizeof(tmp->chan->exten));
01361       else
01362          ast_copy_string(tmp->chan->exten, chan->exten, sizeof(tmp->chan->exten));
01363 
01364       /* Place the call, but don't wait on the answer */
01365       res = ast_call(tmp->chan, numsubst, 0);
01366 
01367       /* Save the info in cdr's that we called them */
01368       if (chan->cdr)
01369          ast_cdr_setdestchan(chan->cdr, tmp->chan->name);
01370 
01371       /* check the results of ast_call */
01372       if (res) {
01373          /* Again, keep going even if there's an error */
01374          if (option_debug)
01375             ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
01376          if (option_verbose > 2)
01377             ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", numsubst);
01378          if (tmp->chan->hangupcause) {
01379             chan->hangupcause = tmp->chan->hangupcause;
01380          }
01381          ast_hangup(tmp->chan);
01382          tmp->chan = NULL;
01383          free(tmp);
01384          continue;
01385       } else {
01386          senddialevent(chan, tmp->chan);
01387          if (option_verbose > 2)
01388             ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", numsubst);
01389          if (!ast_test_flag(peerflags, OPT_ORIGINAL_CLID))
01390             ast_set_callerid(tmp->chan, S_OR(chan->macroexten, chan->exten), get_cid_name(cidname, sizeof(cidname), chan), NULL);
01391       }
01392       /* Put them in the list of outgoing thingies...  We're ready now. 
01393          XXX If we're forcibly removed, these outgoing calls won't get
01394          hung up XXX */
01395       ast_set_flag(tmp, DIAL_STILLGOING); 
01396       tmp->next = outgoing;
01397       outgoing = tmp;
01398       /* If this line is up, don't try anybody else */
01399       if (outgoing->chan->_state == AST_STATE_UP)
01400          break;
01401    }
01402    
01403    if (ast_strlen_zero(args.timeout)) {
01404       to = -1;
01405    } else {
01406       to = atoi(args.timeout);
01407       if (to > 0)
01408          to *= 1000;
01409       else
01410          ast_log(LOG_WARNING, "Invalid timeout specified: '%s'\n", args.timeout);
01411    }
01412 
01413    if (!outgoing) {
01414       strcpy(status, "CHANUNAVAIL");
01415       if(fulldial == num_dialed) {
01416          res = -1;
01417          goto out;
01418       }
01419    } else {
01420       /* Our status will at least be NOANSWER */
01421       strcpy(status, "NOANSWER");
01422       if (ast_test_flag(outgoing, OPT_MUSICBACK)) {
01423          moh = 1;
01424          if (!ast_strlen_zero(opt_args[OPT_ARG_MUSICBACK])) {
01425             char *original_moh = ast_strdupa(chan->musicclass);
01426             ast_string_field_set(chan, musicclass, opt_args[OPT_ARG_MUSICBACK]);
01427             ast_moh_start(chan, opt_args[OPT_ARG_MUSICBACK], NULL);
01428             ast_string_field_set(chan, musicclass, original_moh);
01429          } else {
01430             ast_moh_start(chan, NULL, NULL);
01431          }
01432          ast_indicate(chan, AST_CONTROL_PROGRESS);
01433       } else if (ast_test_flag(outgoing, OPT_RINGBACK)) {
01434          ast_indicate(chan, AST_CONTROL_RINGING);
01435          sentringing++;
01436       }
01437    }
01438 
01439    time(&start_time);
01440    peer = wait_for_answer(chan, outgoing, &to, peerflags, &sentringing, status, sizeof(status), numbusy, numnochan, numcongestion, ast_test_flag(&opts, OPT_PRIORITY_JUMP), &result);
01441 
01442    /* The ast_channel_datastore_remove() function could fail here if the
01443     * datastore was moved to another channel during a masquerade. If this is
01444     * the case, don't free the datastore here because later, when the channel
01445     * to which the datastore was moved hangs up, it will attempt to free this
01446     * datastore again, causing a crash
01447     */
01448    if (!ast_channel_datastore_remove(chan, datastore))
01449       ast_channel_datastore_free(datastore);
01450    if (!peer) {
01451       if (result) {
01452          res = result;
01453       } else if (to) { /* Musta gotten hung up */
01454          res = -1;
01455       } else { /* Nobody answered, next please? */
01456          res = 0;
01457       }
01458       /* almost done, although the 'else' block is 400 lines */
01459    } else {
01460       const char *number;
01461 
01462       strcpy(status, "ANSWER");
01463       pbx_builtin_setvar_helper(chan, "DIALSTATUS", status);
01464       /* Ah ha!  Someone answered within the desired timeframe.  Of course after this
01465          we will always return with -1 so that it is hung up properly after the 
01466          conversation.  */
01467       hanguptree(outgoing, peer);
01468       outgoing = NULL;
01469       /* If appropriate, log that we have a destination channel */
01470       if (chan->cdr)
01471          ast_cdr_setdestchan(chan->cdr, peer->name);
01472       if (peer->name)
01473          pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", peer->name);
01474 
01475       number = pbx_builtin_getvar_helper(peer, "DIALEDPEERNUMBER");
01476       if (!number)
01477          number = numsubst;
01478       pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", number);
01479       if (!ast_strlen_zero(args.url) && ast_channel_supports_html(peer) ) {
01480          if (option_debug)
01481             ast_log(LOG_DEBUG, "app_dial: sendurl=%s.\n", args.url);
01482          ast_channel_sendurl( peer, args.url );
01483       }
01484       if ( (ast_test_flag(&opts, OPT_PRIVACY) || ast_test_flag(&opts, OPT_SCREENING)) && privdb_val == AST_PRIVACY_UNKNOWN) {
01485          int res2;
01486          int loopcount = 0;
01487 
01488          /* Get the user's intro, store it in priv-callerintros/$CID, 
01489             unless it is already there-- this should be done before the 
01490             call is actually dialed  */
01491 
01492          /* all ring indications and moh for the caller has been halted as soon as the 
01493             target extension was picked up. We are going to have to kill some
01494             time and make the caller believe the peer hasn't picked up yet */
01495 
01496          if (ast_test_flag(&opts, OPT_MUSICBACK) && !ast_strlen_zero(opt_args[OPT_ARG_MUSICBACK])) {
01497             char *original_moh = ast_strdupa(chan->musicclass);
01498             ast_indicate(chan, -1);
01499             ast_string_field_set(chan, musicclass, opt_args[OPT_ARG_MUSICBACK]);
01500             ast_moh_start(chan, opt_args[OPT_ARG_MUSICBACK], NULL);
01501             ast_string_field_set(chan, musicclass, original_moh);
01502          } else if (ast_test_flag(&opts, OPT_RINGBACK)) {
01503             ast_indicate(chan, AST_CONTROL_RINGING);
01504             sentringing++;
01505          }
01506 
01507          /* Start autoservice on the other chan ?? */
01508          res2 = ast_autoservice_start(chan);
01509          /* Now Stream the File */
01510          for (loopcount = 0; loopcount < 3; loopcount++) {
01511             if (res2 && loopcount == 0)   /* error in ast_autoservice_start() */
01512                break;
01513             if (!res2)  /* on timeout, play the message again */
01514                res2 = ast_play_and_wait(peer,"priv-callpending");
01515             if (!valid_priv_reply(&opts, res2))
01516                res2 = 0;
01517             /* priv-callpending script: 
01518                "I have a caller waiting, who introduces themselves as:"
01519             */
01520             if (!res2)
01521                res2 = ast_play_and_wait(peer,privintro);
01522             if (!valid_priv_reply(&opts, res2))
01523                res2 = 0;
01524             /* now get input from the called party, as to their choice */
01525             if( !res2 ) {
01526                /* XXX can we have both, or they are mutually exclusive ? */
01527                if( ast_test_flag(&opts, OPT_PRIVACY) )
01528                   res2 = ast_play_and_wait(peer,"priv-callee-options");
01529                if( ast_test_flag(&opts, OPT_SCREENING) )
01530                   res2 = ast_play_and_wait(peer,"screen-callee-options");
01531             }
01532             /*! \page DialPrivacy Dial Privacy scripts
01533             \par priv-callee-options script:
01534                "Dial 1 if you wish this caller to reach you directly in the future,
01535                   and immediately connect to their incoming call
01536                 Dial 2 if you wish to send this caller to voicemail now and 
01537                   forevermore.
01538                 Dial 3 to send this caller to the torture menus, now and forevermore.
01539                 Dial 4 to send this caller to a simple "go away" menu, now and forevermore.
01540                 Dial 5 to allow this caller to come straight thru to you in the future,
01541                   but right now, just this once, send them to voicemail."
01542             \par screen-callee-options script:
01543                "Dial 1 if you wish to immediately connect to the incoming call
01544                 Dial 2 if you wish to send this caller to voicemail.
01545                 Dial 3 to send this caller to the torture menus.
01546                 Dial 4 to send this caller to a simple "go away" menu.
01547             */
01548             if (valid_priv_reply(&opts, res2))
01549                break;
01550             /* invalid option */
01551             res2 = ast_play_and_wait(peer, "vm-sorry");
01552          }
01553 
01554          if (ast_test_flag(&opts, OPT_MUSICBACK)) {
01555             ast_moh_stop(chan);
01556          } else if (ast_test_flag(&opts, OPT_RINGBACK)) {
01557             ast_indicate(chan, -1);
01558             sentringing=0;
01559          }
01560          ast_autoservice_stop(chan);
01561 
01562          switch (res2) {
01563          case '1':
01564             if( ast_test_flag(&opts, OPT_PRIVACY) ) {
01565                if (option_verbose > 2)
01566                   ast_verbose(VERBOSE_PREFIX_3 "--Set privacy database entry %s/%s to ALLOW\n",
01567                           opt_args[OPT_ARG_PRIVACY], privcid);
01568                ast_privacy_set(opt_args[OPT_ARG_PRIVACY], privcid, AST_PRIVACY_ALLOW);
01569             }
01570             break;
01571          case '2':
01572             if( ast_test_flag(&opts, OPT_PRIVACY) ) {
01573                if (option_verbose > 2)
01574                   ast_verbose(VERBOSE_PREFIX_3 "--Set privacy database entry %s/%s to DENY\n",
01575                           opt_args[OPT_ARG_PRIVACY], privcid);
01576                ast_privacy_set(opt_args[OPT_ARG_PRIVACY], privcid, AST_PRIVACY_DENY);
01577             }
01578             ast_copy_string(status, "NOANSWER", sizeof(status));
01579             ast_hangup(peer); /* hang up on the callee -- he didn't want to talk anyway! */
01580             res=0;
01581             goto out;
01582          case '3':
01583             if( ast_test_flag(&opts, OPT_PRIVACY) ) {
01584                if (option_verbose > 2)
01585                   ast_verbose(VERBOSE_PREFIX_3 "--Set privacy database entry %s/%s to TORTURE\n",
01586                           opt_args[OPT_ARG_PRIVACY], privcid);
01587                ast_privacy_set(opt_args[OPT_ARG_PRIVACY], privcid, AST_PRIVACY_TORTURE);
01588             }
01589             ast_copy_string(status, "TORTURE", sizeof(status));
01590             
01591             res = 0;
01592             ast_hangup(peer); /* hang up on the caller -- he didn't want to talk anyway! */
01593             goto out; /* Is this right? */
01594          case '4':
01595             if( ast_test_flag(&opts, OPT_PRIVACY) ) {
01596                if (option_verbose > 2)
01597                   ast_verbose(VERBOSE_PREFIX_3 "--Set privacy database entry %s/%s to KILL\n",
01598                           opt_args[OPT_ARG_PRIVACY], privcid);
01599                ast_privacy_set(opt_args[OPT_ARG_PRIVACY], privcid, AST_PRIVACY_KILL);
01600             }
01601 
01602             ast_copy_string(status, "DONTCALL", sizeof(status));
01603             res = 0;
01604             ast_hangup(peer); /* hang up on the caller -- he didn't want to talk anyway! */
01605             goto out; /* Is this right? */
01606          case '5':
01607             if( ast_test_flag(&opts, OPT_PRIVACY) ) {
01608                if (option_verbose > 2)
01609                   ast_verbose(VERBOSE_PREFIX_3 "--Set privacy database entry %s/%s to ALLOW\n",
01610                           opt_args[OPT_ARG_PRIVACY], privcid);
01611                ast_privacy_set(opt_args[OPT_ARG_PRIVACY], privcid, AST_PRIVACY_ALLOW);
01612                ast_hangup(peer); /* hang up on the caller -- he didn't want to talk anyway! */
01613                res=0;
01614                goto out;
01615             } /* if not privacy, then 5 is the same as "default" case */
01616          default: /* bad input or -1 if failure to start autoservice */
01617             /* well, if the user messes up, ... he had his chance... What Is The Best Thing To Do?  */
01618             /* well, there seems basically two choices. Just patch the caller thru immediately,
01619                  or,... put 'em thru to voicemail. */
01620             /* since the callee may have hung up, let's do the voicemail thing, no database decision */
01621             ast_log(LOG_NOTICE, "privacy: no valid response from the callee. Sending the caller to voicemail, the callee isn't responding\n");
01622             ast_hangup(peer); /* hang up on the callee -- he didn't want to talk anyway! */
01623             res=0;
01624             goto out;
01625          }
01626 
01627          /* XXX once again, this path is only taken in the case '1', so it could be
01628           * moved there, although i am not really sure that this is correct - maybe
01629           * the check applies to other cases as well.
01630           */
01631          /* if the intro is NOCALLERID, then there's no reason to leave it on disk, it'll 
01632             just clog things up, and it's not useful information, not being tied to a CID */
01633          if( strncmp(privcid,"NOCALLERID",10) == 0 || ast_test_flag(&opts, OPT_SCREEN_NOINTRO) ) {
01634             delprivintro = 1;
01635          }
01636       }
01637       if (!ast_test_flag(&opts, OPT_ANNOUNCE) || ast_strlen_zero(opt_args[OPT_ARG_ANNOUNCE])) {
01638          res = 0;
01639       } else {
01640          int digit = 0;
01641          struct ast_channel *chans[2];
01642          struct ast_channel *active_chan;
01643 
01644          chans[0] = chan;
01645          chans[1] = peer;
01646 
01647          /* we need to stream the announcment while monitoring the caller for a hangup */
01648 
01649          /* stream the file */
01650          res = ast_streamfile(peer, opt_args[OPT_ARG_ANNOUNCE], peer->language);
01651          if (res) {
01652             res = 0;
01653             ast_log(LOG_ERROR, "error streaming file '%s' to callee\n", opt_args[OPT_ARG_ANNOUNCE]);
01654          }
01655 
01656          ast_set_flag(peer, AST_FLAG_END_DTMF_ONLY);
01657          while (peer->stream) {
01658             int ms;
01659 
01660             ms = ast_sched_wait(peer->sched);
01661 
01662             if (ms < 0 && !peer->timingfunc) {
01663                ast_stopstream(peer);
01664                break;
01665             }
01666             if (ms < 0)
01667                ms = 1000;
01668 
01669             active_chan = ast_waitfor_n(chans, 2, &ms);
01670             if (active_chan) {
01671                struct ast_frame *fr = ast_read(active_chan);
01672                if (!fr) {
01673                   ast_hangup(peer);
01674                   res = -1;
01675                   goto done;
01676                }
01677                switch(fr->frametype) {
01678                   case AST_FRAME_DTMF_END:
01679                      digit = fr->subclass;
01680                      if (active_chan == peer && strchr(AST_DIGIT_ANY, res)) {
01681                         ast_stopstream(peer);
01682                         res = ast_senddigit(chan, digit);
01683                      }
01684                      break;
01685                   case AST_FRAME_CONTROL:
01686                      switch (fr->subclass) {
01687                         case AST_CONTROL_HANGUP:
01688                            ast_frfree(fr);
01689                            ast_hangup(peer);
01690                            res = -1;
01691                            goto done;
01692                         default:
01693                            break;
01694                      }
01695                      break;
01696                   default:
01697                      /* Ignore all others */
01698                      break;
01699                }
01700                ast_frfree(fr);
01701             }
01702             ast_sched_runq(peer->sched);
01703          }
01704          ast_clear_flag(peer, AST_FLAG_END_DTMF_ONLY);
01705       }
01706 
01707       if (chan && peer && ast_test_flag(&opts, OPT_GOTO) && !ast_strlen_zero(opt_args[OPT_ARG_GOTO])) {
01708          replace_macro_delimiter(opt_args[OPT_ARG_GOTO]);
01709          ast_parseable_goto(chan, opt_args[OPT_ARG_GOTO]);
01710          /* peer goes to the same context and extension as chan, so just copy info from chan*/
01711          ast_copy_string(peer->context, chan->context, sizeof(peer->context));
01712          ast_copy_string(peer->exten, chan->exten, sizeof(peer->exten));
01713          peer->priority = chan->priority + 2;
01714          ast_pbx_start(peer);
01715          hanguptree(outgoing, NULL);
01716          if (continue_exec)
01717             *continue_exec = 1;
01718          res = 0;
01719          goto done;
01720       }
01721 
01722       if (ast_test_flag(&opts, OPT_CALLEE_MACRO) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_MACRO])) {
01723          struct ast_app *theapp;
01724          const char *macro_result;
01725 
01726          res = ast_autoservice_start(chan);
01727          if (res) {
01728             ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
01729             res = -1;
01730          }
01731 
01732          theapp = pbx_findapp("Macro");
01733 
01734          if (theapp && !res) {   /* XXX why check res here ? */
01735             replace_macro_delimiter(opt_args[OPT_ARG_CALLEE_MACRO]);
01736             res = pbx_exec(peer, theapp, opt_args[OPT_ARG_CALLEE_MACRO]);
01737             ast_log(LOG_DEBUG, "Macro exited with status %d\n", res);
01738             res = 0;
01739          } else {
01740             ast_log(LOG_ERROR, "Could not find application Macro\n");
01741             res = -1;
01742          }
01743 
01744          if (ast_autoservice_stop(chan) < 0) {
01745             res = -1;
01746          }
01747 
01748          if (!res && (macro_result = pbx_builtin_getvar_helper(peer, "MACRO_RESULT"))) {
01749                char *macro_transfer_dest;
01750 
01751                if (!strcasecmp(macro_result, "BUSY")) {
01752                   ast_copy_string(status, macro_result, sizeof(status));
01753                   if (ast_opt_priority_jumping || ast_test_flag(&opts, OPT_PRIORITY_JUMP)) {
01754                      if (!ast_goto_if_exists(chan, NULL, NULL, chan->priority + 101)) {
01755                         ast_set_flag(peerflags, OPT_GO_ON);
01756                      }
01757                   } else
01758                      ast_set_flag(peerflags, OPT_GO_ON);
01759                   res = -1;
01760                } else if (!strcasecmp(macro_result, "CONGESTION") || !strcasecmp(macro_result, "CHANUNAVAIL")) {
01761                   ast_copy_string(status, macro_result, sizeof(status));
01762                   ast_set_flag(peerflags, OPT_GO_ON); 
01763                   res = -1;
01764                } else if (!strcasecmp(macro_result, "CONTINUE")) {
01765                   /* hangup peer and keep chan alive assuming the macro has changed 
01766                      the context / exten / priority or perhaps 
01767                      the next priority in the current exten is desired.
01768                   */
01769                   ast_set_flag(peerflags, OPT_GO_ON); 
01770                   res = -1;
01771                } else if (!strcasecmp(macro_result, "ABORT")) {
01772                   /* Hangup both ends unless the caller has the g flag */
01773                   res = -1;
01774                } else if (!strncasecmp(macro_result, "GOTO:", 5) && (macro_transfer_dest = ast_strdupa(macro_result + 5))) {
01775                   res = -1;
01776                   /* perform a transfer to a new extension */
01777                   if (strchr(macro_transfer_dest, '^')) { /* context^exten^priority*/
01778                      replace_macro_delimiter(macro_transfer_dest);
01779                      if (!ast_parseable_goto(chan, macro_transfer_dest))
01780                         ast_set_flag(peerflags, OPT_GO_ON);
01781 
01782                   }
01783                }
01784          }
01785       }
01786 
01787       if (!res) {
01788          if (calldurationlimit > 0) {
01789             peer->whentohangup = time(NULL) + calldurationlimit;
01790          } else if (calldurationlimit != -1 && timelimit > 0) {
01791             /* Not enough granularity to make it less, but we can't use the special value 0 */
01792             peer->whentohangup = time(NULL) + 1;
01793          }
01794          if (!ast_strlen_zero(dtmfcalled)) { 
01795             if (option_verbose > 2)
01796                ast_verbose(VERBOSE_PREFIX_3 "Sending DTMF '%s' to the called party.\n", dtmfcalled);
01797             res = ast_dtmf_stream(peer,chan,dtmfcalled,250);
01798          }
01799          if (!ast_strlen_zero(dtmfcalling)) {
01800             if (option_verbose > 2)
01801                ast_verbose(VERBOSE_PREFIX_3 "Sending DTMF '%s' to the calling party.\n", dtmfcalling);
01802             res = ast_dtmf_stream(chan,peer,dtmfcalling,250);
01803          }
01804       }
01805 
01806       if (!res) {
01807          struct ast_bridge_config config;
01808 
01809          memset(&config,0,sizeof(struct ast_bridge_config));
01810          if (play_to_caller)
01811             ast_set_flag(&(config.features_caller), AST_FEATURE_PLAY_WARNING);
01812          if (play_to_callee)
01813             ast_set_flag(&(config.features_callee), AST_FEATURE_PLAY_WARNING);
01814          if (ast_test_flag(peerflags, OPT_CALLEE_TRANSFER))
01815             ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
01816          if (ast_test_flag(peerflags, OPT_CALLER_TRANSFER))
01817             ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
01818          if (ast_test_flag(peerflags, OPT_CALLEE_HANGUP))
01819             ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
01820          if (ast_test_flag(peerflags, OPT_CALLER_HANGUP))
01821             ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
01822          if (ast_test_flag(peerflags, OPT_CALLEE_MONITOR))
01823             ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
01824          if (ast_test_flag(peerflags, OPT_CALLER_MONITOR)) 
01825             ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
01826          if (ast_test_flag(peerflags, OPT_CALLEE_PARK))
01827             ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
01828          if (ast_test_flag(peerflags, OPT_CALLER_PARK))
01829             ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
01830          if (ast_test_flag(peerflags, OPT_GO_ON))
01831             ast_set_flag(&(config.features_caller), AST_FEATURE_NO_H_EXTEN);
01832 
01833          config.timelimit = timelimit;
01834          config.play_warning = play_warning;
01835          config.warning_freq = warning_freq;
01836          config.warning_sound = warning_sound;
01837          config.end_sound = end_sound;
01838          config.start_sound = start_sound;
01839          config.end_bridge_callback = end_bridge_callback;
01840          config.end_bridge_callback_data = chan;
01841          config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
01842          if (moh) {
01843             moh = 0;
01844             ast_moh_stop(chan);
01845          } else if (sentringing) {
01846             sentringing = 0;
01847             ast_indicate(chan, -1);
01848          }
01849          /* Be sure no generators are left on it */
01850          ast_deactivate_generator(chan);
01851          /* Make sure channels are compatible */
01852          res = ast_channel_make_compatible(chan, peer);
01853          if (res < 0) {
01854             ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", chan->name, peer->name);
01855             ast_hangup(peer);
01856             res = -1;
01857             goto done;
01858          }
01859          if (opermode && 
01860             (((!strncasecmp(chan->name,"Zap",3)) && (!strncasecmp(peer->name,"Zap",3))) ||
01861              ((!strncasecmp(chan->name,"Dahdi",5)) && (!strncasecmp(peer->name,"Dahdi",5)))))
01862          {
01863             struct oprmode oprmode;
01864 
01865             oprmode.peer = peer;
01866             oprmode.mode = opermode;
01867 
01868             ast_channel_setoption(chan,
01869                AST_OPTION_OPRMODE,&oprmode,sizeof(struct oprmode),0);
01870          }
01871          res = ast_bridge_call(chan,peer,&config);
01872       } else {
01873          res = -1;
01874       }
01875 
01876       if (!chan->_softhangup)
01877          chan->hangupcause = peer->hangupcause;
01878       ast_hangup(peer);
01879    }  
01880 out:
01881    if (moh) {
01882       moh = 0;
01883       ast_moh_stop(chan);
01884    } else if (sentringing) {
01885       sentringing = 0;
01886       ast_indicate(chan, -1);
01887    }
01888    if (delprivintro) {
01889       ast_filedelete(privintro, NULL);
01890       if(ast_fileexists(privintro, NULL, NULL) > 0) {
01891          ast_log(LOG_NOTICE,"privacy: ast_filedelete didn't do its job on %s\n", privintro);
01892       } else if (option_verbose > 2) {
01893          ast_verbose(VERBOSE_PREFIX_3 "Successfully deleted %s intro file\n", privintro);
01894       }
01895    }
01896 
01897    ast_rtp_early_bridge(chan, NULL);
01898    hanguptree(outgoing, NULL);
01899    pbx_builtin_setvar_helper(chan, "DIALSTATUS", status);
01900    if (option_debug)
01901       ast_log(LOG_DEBUG, "Exiting with DIALSTATUS=%s (HANGUPCAUSE=%d)\n", status, chan->hangupcause);
01902    
01903    if (ast_test_flag(peerflags, OPT_GO_ON) && !chan->_softhangup) {
01904       if (calldurationlimit)
01905          chan->whentohangup = 0;
01906       res = 0;
01907    }
01908 done:
01909    ast_module_user_remove(u);    
01910    return res;
01911 }
01912 
01913 static int dial_exec(struct ast_channel *chan, void *data)
01914 {
01915    struct ast_flags peerflags;
01916 
01917    memset(&peerflags, 0, sizeof(peerflags));
01918 
01919    return dial_exec_full(chan, data, &peerflags, NULL);
01920 }
01921 
01922 static int retrydial_exec(struct ast_channel *chan, void *data)
01923 {
01924    char *announce = NULL, *dialdata = NULL;
01925    const char *context = NULL;
01926    int sleep = 0, loops = 0, res = -1;
01927    struct ast_module_user *u;
01928    struct ast_flags peerflags;
01929    
01930    if (ast_strlen_zero(data)) {
01931       ast_log(LOG_WARNING, "RetryDial requires an argument!\n");
01932       return -1;
01933    }  
01934 
01935    u = ast_module_user_add(chan);
01936 
01937    announce = ast_strdupa(data);
01938 
01939    memset(&peerflags, 0, sizeof(peerflags));
01940 
01941    if ((dialdata = strchr(announce, '|'))) {
01942       *dialdata++ = '\0';
01943       if (sscanf(dialdata, "%30d", &sleep) == 1) {
01944          sleep *= 1000;
01945       } else {
01946          ast_log(LOG_ERROR, "%s requires the numerical argument <sleep>\n",rapp);
01947          goto done;
01948       }
01949       if ((dialdata = strchr(dialdata, '|'))) {
01950          *dialdata++ = '\0';
01951          if (sscanf(dialdata, "%30d", &loops) != 1) {
01952             ast_log(LOG_ERROR, "%s requires the numerical argument <loops>\n",rapp);
01953             goto done;
01954          }
01955       }
01956    }
01957    
01958    if (dialdata && (dialdata = strchr(dialdata, '|'))) {
01959       *dialdata++ = '\0';
01960    } else {
01961       ast_log(LOG_ERROR, "%s requires more arguments\n",rapp);
01962       goto done;
01963    }
01964       
01965    if (sleep < 1000)
01966       sleep = 10000;
01967 
01968    if (!loops)
01969       loops = -1; /* run forever */
01970    
01971    context = pbx_builtin_getvar_helper(chan, "EXITCONTEXT");
01972 
01973    res = 0;
01974    while (loops) {
01975       int continue_exec;
01976 
01977       chan->data = "Retrying";
01978       if (ast_test_flag(chan, AST_FLAG_MOH))
01979          ast_moh_stop(chan);
01980 
01981       res = dial_exec_full(chan, dialdata, &peerflags, &continue_exec);
01982       if (continue_exec)
01983          break;
01984 
01985       if (res == 0) {
01986          if (ast_test_flag(&peerflags, OPT_DTMF_EXIT)) {
01987             if (!ast_strlen_zero(announce)) {
01988                if (ast_fileexists(announce, NULL, chan->language) > 0) {
01989                   if(!(res = ast_streamfile(chan, announce, chan->language)))                      
01990                      ast_waitstream(chan, AST_DIGIT_ANY);
01991                } else
01992                   ast_log(LOG_WARNING, "Announce file \"%s\" specified in Retrydial does not exist\n", announce);
01993             }
01994             if (!res && sleep) {
01995                if (!ast_test_flag(chan, AST_FLAG_MOH))
01996                   ast_moh_start(chan, NULL, NULL);
01997                res = ast_waitfordigit(chan, sleep);
01998             }
01999          } else {
02000             if (!ast_strlen_zero(announce)) {
02001                if (ast_fileexists(announce, NULL, chan->language) > 0) {
02002                   if (!(res = ast_streamfile(chan, announce, chan->language)))
02003                      res = ast_waitstream(chan, "");
02004                } else
02005                   ast_log(LOG_WARNING, "Announce file \"%s\" specified in Retrydial does not exist\n", announce);
02006             }
02007             if (sleep) {
02008                if (!ast_test_flag(chan, AST_FLAG_MOH))
02009                   ast_moh_start(chan, NULL, NULL);
02010                if (!res)
02011                   res = ast_waitfordigit(chan, sleep);
02012             }
02013          }
02014       }
02015 
02016       if (res < 0)
02017          break;
02018       else if (res > 0) { /* Trying to send the call elsewhere (1 digit ext) */
02019          if (onedigit_goto(chan, context, (char) res, 1)) {
02020             res = 0;
02021             break;
02022          }
02023       }
02024       loops--;
02025    }
02026    if (loops == 0)
02027       res = 0;
02028    else if (res == 1)
02029       res = 0;
02030 
02031    if (ast_test_flag(chan, AST_FLAG_MOH))
02032       ast_moh_stop(chan);
02033  done:
02034    ast_module_user_remove(u);
02035    return res;
02036 }
02037 
02038 static int unload_module(void)
02039 {
02040    int res;
02041 
02042    res = ast_unregister_application(app);
02043    res |= ast_unregister_application(rapp);
02044 
02045    ast_module_user_hangup_all();
02046    
02047    return res;
02048 }
02049 
02050 static int load_module(void)
02051 {
02052    int res;
02053 
02054    res = ast_register_application(app, dial_exec, synopsis, descrip);
02055    res |= ast_register_application(rapp, retrydial_exec, rsynopsis, rdescrip);
02056    
02057    return res;
02058 }
02059 
02060 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Dialing Application");

Generated on Fri Feb 19 17:12:32 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7