Wed Aug 15 01:24:13 2007

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

Generated on Wed Aug 15 01:24:13 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.3