Sat Sep 16 05:47:39 2006

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

Generated on Sat Sep 16 05:47:39 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.7