Wed Oct 28 15:47:47 2009

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

Generated on Wed Oct 28 15:47:47 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6