Thu May 24 14:21:05 2007

Asterisk developer's documentation


app_dial.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief dial() & retrydial() - Trivial application to dial a channel and send an URL on answer
00022  * 
00023  * \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                      }
00567                      /* If call has been answered, then the eventual hangup is likely to be normal hangup */
00568                      in->hangupcause = AST_CAUSE_NORMAL_CLEARING;
00569                      o->chan->hangupcause = AST_CAUSE_NORMAL_CLEARING;
00570                      break;
00571                   case AST_CONTROL_BUSY:
00572                      if (option_verbose > 2)
00573                         ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
00574                      in->hangupcause = o->chan->hangupcause;
00575                      ast_hangup(o->chan);
00576                      o->chan = NULL;
00577                      ast_clear_flag(o, DIAL_STILLGOING); 
00578                      HANDLE_CAUSE(AST_CAUSE_BUSY, in);
00579                      break;
00580                   case AST_CONTROL_CONGESTION:
00581                      if (option_verbose > 2)
00582                         ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
00583                      in->hangupcause = o->chan->hangupcause;
00584                      ast_hangup(o->chan);
00585                      o->chan = NULL;
00586                      ast_clear_flag(o, DIAL_STILLGOING);
00587                      HANDLE_CAUSE(AST_CAUSE_CONGESTION, in);
00588                      break;
00589                   case AST_CONTROL_RINGING:
00590                      if (option_verbose > 2)
00591                         ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
00592                      if (!(*sentringing) && !ast_test_flag(outgoing, OPT_MUSICBACK)) {
00593                         ast_indicate(in, AST_CONTROL_RINGING);
00594                         (*sentringing)++;
00595                      }
00596                      break;
00597                   case AST_CONTROL_PROGRESS:
00598                      if (option_verbose > 2)
00599                         ast_verbose ( VERBOSE_PREFIX_3 "%s is making progress passing it to %s\n", o->chan->name,in->name);
00600                      if (!ast_test_flag(outgoing, OPT_RINGBACK))
00601                         ast_indicate(in, AST_CONTROL_PROGRESS);
00602                      break;
00603                   case AST_CONTROL_VIDUPDATE:
00604                      if (option_verbose > 2)
00605                         ast_verbose ( VERBOSE_PREFIX_3 "%s requested a video update, passing it to %s\n", o->chan->name,in->name);
00606                      ast_indicate(in, AST_CONTROL_VIDUPDATE);
00607                      break;
00608                   case AST_CONTROL_PROCEEDING:
00609                      if (option_verbose > 2)
00610                         ast_verbose ( VERBOSE_PREFIX_3 "%s is proceeding passing it to %s\n", o->chan->name,in->name);
00611                      if (!ast_test_flag(outgoing, OPT_RINGBACK))
00612                         ast_indicate(in, AST_CONTROL_PROCEEDING);
00613                      break;
00614                   case AST_CONTROL_HOLD:
00615                      if (option_verbose > 2)
00616                         ast_verbose(VERBOSE_PREFIX_3 "Call on %s placed on hold\n", o->chan->name);
00617                      ast_indicate(in, AST_CONTROL_HOLD);
00618                      break;
00619                   case AST_CONTROL_UNHOLD:
00620                      if (option_verbose > 2)
00621                         ast_verbose(VERBOSE_PREFIX_3 "Call on %s left from hold\n", o->chan->name);
00622                      ast_indicate(in, AST_CONTROL_UNHOLD);
00623                      break;
00624                   case AST_CONTROL_OFFHOOK:
00625                   case AST_CONTROL_FLASH:
00626                      /* Ignore going off hook and flash */
00627                      break;
00628                   case -1:
00629                      if (!ast_test_flag(outgoing, OPT_RINGBACK | OPT_MUSICBACK)) {
00630                         if (option_verbose > 2)
00631                            ast_verbose( VERBOSE_PREFIX_3 "%s stopped sounds\n", o->chan->name);
00632                         ast_indicate(in, -1);
00633                         (*sentringing) = 0;
00634                      }
00635                      break;
00636                   default:
00637                      ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
00638                   }
00639                } else if (single && (f->frametype == AST_FRAME_VOICE) && 
00640                         !(ast_test_flag(outgoing, OPT_RINGBACK|OPT_MUSICBACK))) {
00641                   if (ast_write(in, f)) 
00642                      ast_log(LOG_DEBUG, "Unable to forward frame\n");
00643                } else if (single && (f->frametype == AST_FRAME_IMAGE) && 
00644                         !(ast_test_flag(outgoing, OPT_RINGBACK|OPT_MUSICBACK))) {
00645                   if (ast_write(in, f))
00646                      ast_log(LOG_DEBUG, "Unable to forward image\n");
00647                } else if (single && (f->frametype == AST_FRAME_TEXT) && 
00648                         !(ast_test_flag(outgoing, OPT_RINGBACK|OPT_MUSICBACK))) {
00649                   if (ast_write(in, f))
00650                      ast_log(LOG_DEBUG, "Unable to text\n");
00651                } else if (single && (f->frametype == AST_FRAME_HTML) && !ast_test_flag(outgoing, DIAL_NOFORWARDHTML))
00652                   ast_channel_sendhtml(in, f->subclass, f->data, f->datalen);
00653 
00654                ast_frfree(f);
00655             } else {
00656                in->hangupcause = o->chan->hangupcause;
00657                ast_hangup(o->chan);
00658                o->chan = NULL;
00659                ast_clear_flag(o, DIAL_STILLGOING);
00660                HANDLE_CAUSE(in->hangupcause, in);
00661             }
00662          }
00663          o = o->next;
00664       }
00665       if (winner == in) {
00666          f = ast_read(in);
00667 #if 0
00668          if (f && (f->frametype != AST_FRAME_VOICE))
00669             printf("Frame type: %d, %d\n", f->frametype, f->subclass);
00670          else if (!f || (f->frametype != AST_FRAME_VOICE))
00671             printf("Hangup received on %s\n", in->name);
00672 #endif
00673          if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
00674             /* Got hung up */
00675             *to=-1;
00676             strcpy(status, "CANCEL");
00677             if (f)
00678                ast_frfree(f);
00679             return NULL;
00680          }
00681 
00682          if (f && (f->frametype == AST_FRAME_DTMF)) {
00683             if (ast_test_flag(peerflags, OPT_DTMF_EXIT)) {
00684                context = pbx_builtin_getvar_helper(in, "EXITCONTEXT");
00685                if (onedigit_goto(in, context, (char) f->subclass, 1)) {
00686                   if (option_verbose > 3)
00687                      ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
00688                   *to=0;
00689                   *result = f->subclass;
00690                   strcpy(status, "CANCEL");
00691                   ast_frfree(f);
00692                   return NULL;
00693                }
00694             }
00695 
00696             if (ast_test_flag(peerflags, OPT_CALLER_HANGUP) && 
00697                     (f->subclass == '*')) { /* hmm it it not guarenteed to be '*' anymore. */
00698                if (option_verbose > 3)
00699                   ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
00700                *to=0;
00701                strcpy(status, "CANCEL");
00702                ast_frfree(f);
00703                return NULL;
00704             }
00705          }
00706 
00707          /* Forward HTML stuff */
00708          if (single && f && (f->frametype == AST_FRAME_HTML) && !ast_test_flag(outgoing, DIAL_NOFORWARDHTML)) 
00709             ast_channel_sendhtml(outgoing->chan, f->subclass, f->data, f->datalen);
00710          
00711 
00712          if (single && ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_DTMF)))  {
00713             if (ast_write(outgoing->chan, f))
00714                ast_log(LOG_WARNING, "Unable to forward voice\n");
00715          }
00716          if (single && (f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_VIDUPDATE)) {
00717             if (option_verbose > 2)
00718                ast_verbose ( VERBOSE_PREFIX_3 "%s requested a video update, passing it to %s\n", in->name,outgoing->chan->name);
00719             ast_indicate(outgoing->chan, AST_CONTROL_VIDUPDATE);
00720          }
00721          ast_frfree(f);
00722       }
00723       if (!*to && (option_verbose > 2))
00724          ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
00725    }
00726 
00727    return peer;
00728    
00729 }
00730 
00731 static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags *peerflags)
00732 {
00733    int res=-1;
00734    struct localuser *u;
00735    char *tech, *number, *rest, *cur;
00736    char privcid[256];
00737    char privintro[1024];
00738    struct localuser *outgoing=NULL, *tmp;
00739    struct ast_channel *peer;
00740    int to;
00741    int numbusy = 0;
00742    int numcongestion = 0;
00743    int numnochan = 0;
00744    int cause;
00745    char numsubst[AST_MAX_EXTENSION];
00746    char restofit[AST_MAX_EXTENSION];
00747    char cidname[AST_MAX_EXTENSION];
00748    char toast[80];
00749    char *newnum;
00750    char *l;
00751    int privdb_val=0;
00752    unsigned int calldurationlimit=0;
00753    struct ast_bridge_config config;
00754    long timelimit = 0;
00755    long play_warning = 0;
00756    long warning_freq=0;
00757    char *warning_sound=NULL;
00758    char *end_sound=NULL;
00759    char *start_sound=NULL;
00760    char *dtmfcalled=NULL, *dtmfcalling=NULL;
00761    char *var;
00762    char status[256];
00763    int play_to_caller=0,play_to_callee=0;
00764    int sentringing=0, moh=0;
00765    char *outbound_group = NULL;
00766    char *macro_result = NULL, *macro_transfer_dest = NULL;
00767    int digit = 0, result = 0;
00768    time_t start_time, answer_time, end_time;
00769    struct ast_app *app = NULL;
00770 
00771    char *parse;
00772    AST_DECLARE_APP_ARGS(args,
00773               AST_APP_ARG(peers);
00774               AST_APP_ARG(timeout);
00775               AST_APP_ARG(options);
00776               AST_APP_ARG(url);
00777    );
00778    struct ast_flags opts = { 0, };
00779    char *opt_args[OPT_ARG_ARRAY_SIZE];
00780 
00781    if (ast_strlen_zero(data)) {
00782       ast_log(LOG_WARNING, "Dial requires an argument (technology/number)\n");
00783       return -1;
00784    }
00785 
00786    LOCAL_USER_ADD(u);
00787 
00788    if (!(parse = ast_strdupa(data))) {
00789       ast_log(LOG_WARNING, "Memory allocation failure\n");
00790       LOCAL_USER_REMOVE(u);
00791       return -1;
00792    }
00793    
00794    AST_STANDARD_APP_ARGS(args, parse);
00795 
00796    if (!ast_strlen_zero(args.options)) {
00797       if (ast_app_parse_options(dial_exec_options, &opts, opt_args, args.options)) {
00798          LOCAL_USER_REMOVE(u);
00799          return -1;
00800       }
00801    }
00802 
00803    if (ast_strlen_zero(args.peers)) {
00804       ast_log(LOG_WARNING, "Dial requires an argument (technology/number)\n");
00805       LOCAL_USER_REMOVE(u);
00806       return -1;
00807    }
00808 
00809    if (ast_test_flag(&opts, OPT_DURATION_STOP) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_STOP])) {
00810       calldurationlimit = atoi(opt_args[OPT_ARG_DURATION_STOP]);
00811       if (option_verbose > 2)
00812          ast_verbose(VERBOSE_PREFIX_3 "Setting call duration limit to %d seconds.\n",calldurationlimit);       
00813    }
00814 
00815    if (ast_test_flag(&opts, OPT_SENDDTMF) && !ast_strlen_zero(opt_args[OPT_ARG_SENDDTMF])) {
00816       parse = opt_args[OPT_ARG_SENDDTMF];
00817       dtmfcalled = strsep(&parse, ":");
00818       dtmfcalling = parse;
00819    }
00820 
00821    if (ast_test_flag(&opts, OPT_DURATION_LIMIT) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])) {
00822       char *limit_str, *warning_str, *warnfreq_str;
00823 
00824       parse = opt_args[OPT_ARG_DURATION_LIMIT];
00825       limit_str = strsep(&parse, ":");
00826       warning_str = strsep(&parse, ":");
00827       warnfreq_str = parse;
00828 
00829       timelimit = atol(limit_str);
00830       if (warning_str)
00831          play_warning = atol(warning_str);
00832       if (warnfreq_str)
00833          warning_freq = atol(warnfreq_str);
00834 
00835       if (!timelimit) {
00836          timelimit = play_to_caller = play_to_callee = play_warning = warning_freq = 0;
00837          warning_sound = NULL;
00838       } else if (play_warning > timelimit) {
00839          /* If the first warning is requested _after_ the entire call would end,
00840             and no warning frequency is requested, then turn off the warning. If
00841             a warning frequency is requested, reduce the 'first warning' time by
00842             that frequency until it falls within the call's total time limit.
00843          */
00844 
00845          if (!warning_freq) {
00846             play_warning = 0;
00847          } else {
00848             while (play_warning > timelimit)
00849                play_warning -= warning_freq;
00850             if (play_warning < 1)
00851                play_warning = warning_freq = 0;
00852          }
00853       }
00854 
00855       var = pbx_builtin_getvar_helper(chan,"LIMIT_PLAYAUDIO_CALLER");
00856       play_to_caller = var ? ast_true(var) : 1;
00857       
00858       var = pbx_builtin_getvar_helper(chan,"LIMIT_PLAYAUDIO_CALLEE");
00859       play_to_callee = var ? ast_true(var) : 0;
00860       
00861       if (!play_to_caller && !play_to_callee)
00862          play_to_caller=1;
00863       
00864       var = pbx_builtin_getvar_helper(chan,"LIMIT_WARNING_FILE");
00865       warning_sound = var ? var : "timeleft";
00866       
00867       var = pbx_builtin_getvar_helper(chan,"LIMIT_TIMEOUT_FILE");
00868       end_sound = var ? var : NULL;
00869       
00870       var = pbx_builtin_getvar_helper(chan,"LIMIT_CONNECT_FILE");
00871       start_sound = var ? var : NULL;
00872 
00873       /* undo effect of S(x) in case they are both used */
00874       calldurationlimit = 0; 
00875       /* more efficient do it like S(x) does since no advanced opts*/
00876       if (!play_warning && !start_sound && !end_sound && timelimit) { 
00877          calldurationlimit = timelimit/1000;
00878          timelimit = play_to_caller = play_to_callee = play_warning = warning_freq = 0;
00879       } else if (option_verbose > 2) {
00880          ast_verbose(VERBOSE_PREFIX_3 "Limit Data for this call:\n");
00881          ast_verbose(VERBOSE_PREFIX_3 "- timelimit     = %ld\n", timelimit);
00882          ast_verbose(VERBOSE_PREFIX_3 "- play_warning  = %ld\n", play_warning);
00883          ast_verbose(VERBOSE_PREFIX_3 "- play_to_caller= %s\n", play_to_caller ? "yes" : "no");
00884          ast_verbose(VERBOSE_PREFIX_3 "- play_to_callee= %s\n", play_to_callee ? "yes" : "no");
00885          ast_verbose(VERBOSE_PREFIX_3 "- warning_freq  = %ld\n", warning_freq);
00886          ast_verbose(VERBOSE_PREFIX_3 "- start_sound   = %s\n", start_sound ? start_sound : "UNDEF");
00887          ast_verbose(VERBOSE_PREFIX_3 "- warning_sound = %s\n", warning_sound ? warning_sound : "UNDEF");
00888          ast_verbose(VERBOSE_PREFIX_3 "- end_sound     = %s\n", end_sound ? end_sound : "UNDEF");
00889       }
00890    }
00891 
00892    if (ast_test_flag(&opts, OPT_RESETCDR) && chan->cdr)
00893       ast_cdr_reset(chan->cdr, NULL);
00894    if (ast_test_flag(&opts, OPT_PRIVACY) && ast_strlen_zero(opt_args[OPT_ARG_PRIVACY]))
00895       opt_args[OPT_ARG_PRIVACY] = ast_strdupa(chan->exten);
00896    if (ast_test_flag(&opts, OPT_PRIVACY) || ast_test_flag(&opts, OPT_SCREENING)) {
00897       char callerid[60];
00898 
00899       l = chan->cid.cid_num;
00900       if (!ast_strlen_zero(l)) {
00901          ast_shrink_phone_number(l);
00902          if( ast_test_flag(&opts, OPT_PRIVACY) ) {
00903             if (option_verbose > 2)
00904                ast_verbose( VERBOSE_PREFIX_3  "Privacy DB is '%s', clid is '%s'\n",
00905                        opt_args[OPT_ARG_PRIVACY], l);
00906             privdb_val = ast_privacy_check(opt_args[OPT_ARG_PRIVACY], l);
00907          }
00908          else {
00909             if (option_verbose > 2)
00910                ast_verbose( VERBOSE_PREFIX_3  "Privacy Screening, clid is '%s'\n", l);
00911             privdb_val = AST_PRIVACY_UNKNOWN;
00912          }
00913       } else {
00914          char *tnam, *tn2;
00915 
00916          tnam = ast_strdupa(chan->name);
00917          /* clean the channel name so slashes don't try to end up in disk file name */
00918          for(tn2 = tnam; *tn2; tn2++) {
00919             if( *tn2=='/')
00920                *tn2 = '=';  /* any other chars to be afraid of? */
00921          }
00922          if (option_verbose > 2)
00923             ast_verbose( VERBOSE_PREFIX_3  "Privacy-- callerid is empty\n");
00924 
00925          snprintf(callerid, sizeof(callerid), "NOCALLERID_%s%s", chan->exten, tnam);
00926          l = callerid;
00927          privdb_val = AST_PRIVACY_UNKNOWN;
00928       }
00929       
00930       ast_copy_string(privcid,l,sizeof(privcid));
00931 
00932       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 */  
00933          if (option_verbose > 2)
00934             ast_verbose( VERBOSE_PREFIX_3  "CallerID set (%s); N option set; Screening should be off\n", privcid);
00935          privdb_val = AST_PRIVACY_ALLOW;
00936       }
00937       else if( ast_test_flag(&opts, OPT_SCREEN_NOCLID) && strncmp(privcid,"NOCALLERID",10) == 0 ) {
00938          if (option_verbose > 2)
00939             ast_verbose( VERBOSE_PREFIX_3  "CallerID blank; N option set; Screening should happen; dbval is %d\n", privdb_val);
00940       }
00941       
00942       if( privdb_val == AST_PRIVACY_DENY ) {
00943          strcpy(status, "NOANSWER");
00944          ast_verbose( VERBOSE_PREFIX_3  "Privacy DB reports PRIVACY_DENY for this callerid. Dial reports unavailable\n");
00945          res=0;
00946          goto out;
00947       }
00948       else if( privdb_val == AST_PRIVACY_KILL ) {
00949          strcpy(status, "DONTCALL");
00950          if (option_priority_jumping || ast_test_flag(&opts, OPT_PRIORITY_JUMP)) {
00951             ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 201);
00952          }
00953          res = 0;
00954          goto out; /* Is this right? */
00955       }
00956       else if( privdb_val == AST_PRIVACY_TORTURE ) {
00957          strcpy(status, "TORTURE");
00958          if (option_priority_jumping || ast_test_flag(&opts, OPT_PRIORITY_JUMP)) {
00959             ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 301);
00960          }
00961          res = 0;
00962          goto out; /* is this right??? */
00963       }
00964       else if( privdb_val == AST_PRIVACY_UNKNOWN ) {
00965          /* Get the user's intro, store it in priv-callerintros/$CID, 
00966             unless it is already there-- this should be done before the 
00967             call is actually dialed  */
00968 
00969          /* make sure the priv-callerintros dir actually exists */
00970          snprintf(privintro, sizeof(privintro), "%s/sounds/priv-callerintros", ast_config_AST_VAR_DIR);
00971          if (mkdir(privintro, 0755) && errno != EEXIST) {
00972             ast_log(LOG_WARNING, "privacy: can't create directory priv-callerintros: %s\n", strerror(errno));
00973             res = -1;
00974             goto out;
00975          }
00976 
00977          snprintf(privintro,sizeof(privintro),"priv-callerintros/%s", privcid);
00978          if( ast_fileexists(privintro,NULL,NULL ) > 0 && strncmp(privcid,"NOCALLERID",10) != 0) {
00979             /* the DELUX version of this code would allow this caller the
00980                option to hear and retape their previously recorded intro.
00981             */
00982          }
00983          else {
00984             int duration; /* for feedback from play_and_wait */
00985             /* the file doesn't exist yet. Let the caller submit his
00986                vocal intro for posterity */
00987             /* priv-recordintro script:
00988 
00989                "At the tone, please say your name:"
00990 
00991             */
00992             res = ast_play_and_record(chan, "priv-recordintro", privintro, 4, "gsm", &duration, 128, 2000, 0);  /* NOTE: I've reduced the total time to */
00993                                              /* 4 sec don't think we'll need a lock removed, we 
00994                                                 took care of conflicts by naming the privintro file */
00995             if (res == -1) {
00996                /* Delete the file regardless since they hung up during recording */
00997                                         ast_filedelete(privintro, NULL);
00998                                         if( ast_fileexists(privintro,NULL,NULL ) > 0 )
00999                                                 ast_log(LOG_NOTICE,"privacy: ast_filedelete didn't do its job on %s\n", privintro);
01000                                         else if (option_verbose > 2)
01001                                                 ast_verbose( VERBOSE_PREFIX_3 "Successfully deleted %s intro file\n", privintro);
01002                goto out;
01003             }
01004          }
01005       }
01006    }
01007 
01008    /* If a channel group has been specified, get it for use when we create peer channels */
01009    outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP");
01010 
01011    ast_copy_flags(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID | OPT_CALLER_HANGUP);
01012    cur = args.peers;
01013    do {
01014       /* Remember where to start next time */
01015       rest = strchr(cur, '&');
01016       if (rest) {
01017          *rest = 0;
01018          rest++;
01019       }
01020       /* Get a technology/[device:]number pair */
01021       tech = cur;
01022       number = strchr(tech, '/');
01023       if (!number) {
01024          ast_log(LOG_WARNING, "Dial argument takes format (technology/[device:]number1)\n");
01025          goto out;
01026       }
01027       *number = '\0';
01028       number++;
01029       tmp = malloc(sizeof(struct localuser));
01030       if (!tmp) {
01031          ast_log(LOG_WARNING, "Out of memory\n");
01032          goto out;
01033       }
01034       memset(tmp, 0, sizeof(struct localuser));
01035       if (opts.flags) {
01036          ast_copy_flags(tmp, &opts,
01037                    OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
01038                    OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
01039                    OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
01040                    OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID);
01041          ast_set2_flag(tmp, args.url, DIAL_NOFORWARDHTML);  
01042       }
01043       ast_copy_string(numsubst, number, sizeof(numsubst));
01044       /* If we're dialing by extension, look at the extension to know what to dial */
01045       if ((newnum = strstr(numsubst, "BYEXTENSION"))) {
01046          /* strlen("BYEXTENSION") == 11 */
01047          ast_copy_string(restofit, newnum + 11, sizeof(restofit));
01048          snprintf(newnum, sizeof(numsubst) - (newnum - numsubst), "%s%s", chan->exten,restofit);
01049          if (option_debug)
01050             ast_log(LOG_DEBUG, "Dialing by extension %s\n", numsubst);
01051       }
01052       /* Request the peer */
01053       tmp->chan = ast_request(tech, chan->nativeformats, numsubst, &cause);
01054       if (!tmp->chan) {
01055          /* If we can't, just go on to the next call */
01056          ast_log(LOG_NOTICE, "Unable to create channel of type '%s' (cause %d - %s)\n", tech, cause, ast_cause2str(cause));
01057          HANDLE_CAUSE(cause, chan);
01058          cur = rest;
01059          if (!cur)
01060             chan->hangupcause = cause;
01061          continue;
01062       }
01063       pbx_builtin_setvar_helper(tmp->chan, "DIALEDPEERNUMBER", numsubst);
01064       if (!ast_strlen_zero(tmp->chan->call_forward)) {
01065          char tmpchan[256];
01066          char *stuff;
01067          char *tech;
01068          ast_copy_string(tmpchan, tmp->chan->call_forward, sizeof(tmpchan));
01069          if ((stuff = strchr(tmpchan, '/'))) {
01070             *stuff = '\0';
01071             stuff++;
01072             tech = tmpchan;
01073          } else {
01074             snprintf(tmpchan, sizeof(tmpchan), "%s@%s", tmp->chan->call_forward, tmp->chan->context);
01075             stuff = tmpchan;
01076             tech = "Local";
01077          }
01078          tmp->forwards++;
01079          if (tmp->forwards < AST_MAX_FORWARDS) {
01080             if (option_verbose > 2)
01081                ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", chan->name, tech, stuff, tmp->chan->name);
01082             ast_hangup(tmp->chan);
01083             /* Setup parameters */
01084             tmp->chan = ast_request(tech, chan->nativeformats, stuff, &cause);
01085             if (!tmp->chan)
01086                ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
01087             else
01088                ast_channel_inherit_variables(chan, tmp->chan);
01089          } else {
01090             if (option_verbose > 2)
01091                ast_verbose(VERBOSE_PREFIX_3 "Too many forwards from %s\n", tmp->chan->name);
01092             ast_hangup(tmp->chan);
01093             tmp->chan = NULL;
01094             cause = AST_CAUSE_CONGESTION;
01095          }
01096          if (!tmp->chan) {
01097             HANDLE_CAUSE(cause, chan);
01098             cur = rest;
01099             continue;
01100          }
01101       }
01102 
01103       /* Inherit specially named variables from parent channel */
01104       ast_channel_inherit_variables(chan, tmp->chan);
01105 
01106       tmp->chan->appl = "AppDial";
01107       tmp->chan->data = "(Outgoing Line)";
01108       tmp->chan->whentohangup = 0;
01109       if (tmp->chan->cid.cid_num)
01110          free(tmp->chan->cid.cid_num);
01111       tmp->chan->cid.cid_num = NULL;
01112       if (tmp->chan->cid.cid_name)
01113          free(tmp->chan->cid.cid_name);
01114       tmp->chan->cid.cid_name = NULL;
01115       if (tmp->chan->cid.cid_ani)
01116          free(tmp->chan->cid.cid_ani);
01117       tmp->chan->cid.cid_ani = NULL;
01118 
01119       if (chan->cid.cid_num) 
01120          tmp->chan->cid.cid_num = strdup(chan->cid.cid_num);
01121       if (chan->cid.cid_name) 
01122          tmp->chan->cid.cid_name = strdup(chan->cid.cid_name);
01123       if (chan->cid.cid_ani) 
01124          tmp->chan->cid.cid_ani = strdup(chan->cid.cid_ani);
01125       
01126       /* Copy language from incoming to outgoing */
01127       ast_copy_string(tmp->chan->language, chan->language, sizeof(tmp->chan->language));
01128       ast_copy_string(tmp->chan->accountcode, chan->accountcode, sizeof(tmp->chan->accountcode));
01129       tmp->chan->cdrflags = chan->cdrflags;
01130       if (ast_strlen_zero(tmp->chan->musicclass))
01131          ast_copy_string(tmp->chan->musicclass, chan->musicclass, sizeof(tmp->chan->musicclass));
01132       if (chan->cid.cid_rdnis)
01133          tmp->chan->cid.cid_rdnis = strdup(chan->cid.cid_rdnis);
01134       /* Pass callingpres setting */
01135       tmp->chan->cid.cid_pres = chan->cid.cid_pres;
01136       /* Pass type of number */
01137       tmp->chan->cid.cid_ton = chan->cid.cid_ton;
01138       /* Pass type of tns */
01139       tmp->chan->cid.cid_tns = chan->cid.cid_tns;
01140       /* Presense of ADSI CPE on outgoing channel follows ours */
01141       tmp->chan->adsicpe = chan->adsicpe;
01142       /* Pass the transfer capability */
01143       tmp->chan->transfercapability = chan->transfercapability;
01144 
01145       /* If we have an outbound group, set this peer channel to it */
01146       if (outbound_group)
01147          ast_app_group_set_channel(tmp->chan, outbound_group);
01148 
01149       /* Place the call, but don't wait on the answer */
01150       res = ast_call(tmp->chan, numsubst, 0);
01151 
01152       /* Save the info in cdr's that we called them */
01153       if (chan->cdr)
01154          ast_cdr_setdestchan(chan->cdr, tmp->chan->name);
01155 
01156       /* check the results of ast_call */
01157       if (res) {
01158          /* Again, keep going even if there's an error */
01159          if (option_debug)
01160             ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
01161          else if (option_verbose > 2)
01162             ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", numsubst);
01163          ast_hangup(tmp->chan);
01164          tmp->chan = NULL;
01165          cur = rest;
01166          continue;
01167       } else {
01168          senddialevent(chan, tmp->chan);
01169          if (option_verbose > 2)
01170             ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", numsubst);
01171          if (!ast_test_flag(peerflags, OPT_ORIGINAL_CLID))
01172             ast_set_callerid(tmp->chan, ast_strlen_zero(chan->macroexten) ? chan->exten : chan->macroexten, get_cid_name(cidname, sizeof(cidname), chan), NULL);
01173       }
01174       /* Put them in the list of outgoing thingies...  We're ready now. 
01175          XXX If we're forcibly removed, these outgoing calls won't get
01176          hung up XXX */
01177       ast_set_flag(tmp, DIAL_STILLGOING); 
01178       tmp->next = outgoing;
01179       outgoing = tmp;
01180       /* If this line is up, don't try anybody else */
01181       if (outgoing->chan->_state == AST_STATE_UP)
01182          break;
01183       cur = rest;
01184    } while (cur);
01185    
01186    if (!ast_strlen_zero(args.timeout)) {
01187       to = atoi(args.timeout);
01188       if (to > 0)
01189          to *= 1000;
01190       else
01191          ast_log(LOG_WARNING, "Invalid timeout specified: '%s'\n", args.timeout);
01192    } else
01193       to = -1;
01194 
01195    if (outgoing) {
01196       /* Our status will at least be NOANSWER */
01197       strcpy(status, "NOANSWER");
01198       if (ast_test_flag(outgoing, OPT_MUSICBACK)) {
01199          moh=1;
01200          ast_moh_start(chan, opt_args[OPT_ARG_MUSICBACK]);
01201       } else if (ast_test_flag(outgoing, OPT_RINGBACK)) {
01202          ast_indicate(chan, AST_CONTROL_RINGING);
01203          sentringing++;
01204       }
01205    } else
01206       strcpy(status, "CHANUNAVAIL");
01207 
01208    time(&start_time);
01209    peer = wait_for_answer(chan, outgoing, &to, peerflags, &sentringing, status, sizeof(status), numbusy, numnochan, numcongestion, ast_test_flag(&opts, OPT_PRIORITY_JUMP), &result);
01210    
01211    if (!peer) {
01212       if (result) {
01213          res = result;
01214       } else if (to) 
01215          /* Musta gotten hung up */
01216          res = -1;
01217       else 
01218          /* Nobody answered, next please? */
01219          res = 0;
01220       
01221       goto out;
01222    }
01223    if (peer) {
01224       time(&answer_time);
01225 #ifdef OSP_SUPPORT
01226       /* Once call is answered, ditch the OSP Handle */
01227       pbx_builtin_setvar_helper(chan, "_OSPHANDLE", "");
01228 #endif
01229       strcpy(status, "ANSWER");
01230       /* Ah ha!  Someone answered within the desired timeframe.  Of course after this
01231          we will always return with -1 so that it is hung up properly after the 
01232          conversation.  */
01233       hanguptree(outgoing, peer);
01234       outgoing = NULL;
01235       /* If appropriate, log that we have a destination channel */
01236       if (chan->cdr)
01237          ast_cdr_setdestchan(chan->cdr, peer->name);
01238       if (peer->name)
01239          pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", peer->name);
01240 
01241       number = pbx_builtin_getvar_helper(peer, "DIALEDPEERNUMBER");
01242       if (!number)
01243          number = numsubst;
01244       pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", number);
01245       if (!ast_strlen_zero(args.url) && ast_channel_supports_html(peer) ) {
01246          ast_log(LOG_DEBUG, "app_dial: sendurl=%s.\n", args.url);
01247          ast_channel_sendurl( peer, args.url );
01248       }
01249       if (ast_test_flag(&opts, OPT_PRIVACY) || ast_test_flag(&opts, OPT_SCREENING)) {
01250          int res2;
01251          int loopcount = 0;
01252          if( privdb_val == AST_PRIVACY_UNKNOWN ) {
01253 
01254             /* Get the user's intro, store it in priv-callerintros/$CID, 
01255                unless it is already there-- this should be done before the 
01256                call is actually dialed  */
01257 
01258             /* all ring indications and moh for the caller has been halted as soon as the 
01259                target extension was picked up. We are going to have to kill some
01260                time and make the caller believe the peer hasn't picked up yet */
01261 
01262             if (ast_test_flag(&opts, OPT_MUSICBACK) && !ast_strlen_zero(opt_args[OPT_ARG_MUSICBACK])) {
01263                ast_indicate(chan, -1);
01264                ast_moh_start(chan, opt_args[OPT_ARG_MUSICBACK]);
01265             } else if (ast_test_flag(&opts, OPT_RINGBACK)) {
01266                ast_indicate(chan, AST_CONTROL_RINGING);
01267                sentringing++;
01268             }
01269 
01270             /* Start autoservice on the other chan ?? */
01271             res2 = ast_autoservice_start(chan);
01272             /* Now Stream the File */
01273             if (!res2) {
01274                do {
01275                   if (!res2)
01276                      res2 = ast_play_and_wait(peer,"priv-callpending");
01277                   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! */
01278                      res2 = 0;
01279                   
01280                   /* priv-callpending script: 
01281                      "I have a caller waiting, who introduces themselves as:"
01282                   */
01283                   if (!res2)
01284                      res2 = ast_play_and_wait(peer, privintro);
01285                   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! */
01286                      res2 = 0;
01287                   /* now get input from the called party, as to their choice */
01288                   if (!res2) {
01289                      if( ast_test_flag(&opts, OPT_PRIVACY) )
01290                         res2 = ast_play_and_wait(peer,"priv-callee-options");
01291                      if( ast_test_flag(&opts, OPT_SCREENING) )
01292                         res2 = ast_play_and_wait(peer,"screen-callee-options");
01293                   }
01294                   /* priv-callee-options script:
01295                      "Dial 1 if you wish this caller to reach you directly in the future,
01296                         and immediately connect to their incoming call
01297                       Dial 2 if you wish to send this caller to voicemail now and 
01298                         forevermore.
01299                       Dial 3 to send this callerr to the torture menus, now and forevermore.
01300                       Dial 4 to send this caller to a simple "go away" menu, now and forevermore.
01301                       Dial 5 to allow this caller to come straight thru to you in the future,
01302                   but right now, just this once, send them to voicemail."
01303                   */
01304             
01305                   /* screen-callee-options script:
01306                      "Dial 1 if you wish to immediately connect to the incoming call
01307                       Dial 2 if you wish to send this caller to voicemail.
01308                       Dial 3 to send this callerr to the torture menus.
01309                       Dial 4 to send this caller to a simple "go away" menu.
01310                   */
01311                   if( !res2 || res2 < '1' || (ast_test_flag(&opts, OPT_PRIVACY) && res2 > '5') || (ast_test_flag(&opts, OPT_SCREENING) && res2 > '4') ) {
01312                      /* invalid option */
01313                      res2 = ast_play_and_wait(peer,"vm-sorry");
01314                   }
01315                   loopcount++; /* give the callee a couple chances to make a choice */
01316                } while( (!res2 || res2 < '1' || (ast_test_flag(&opts, OPT_PRIVACY) && res2 > '5') || (ast_test_flag(&opts, OPT_SCREENING) && res2 > '4')) && loopcount < 2 );
01317             }
01318 
01319             switch(res2) {
01320             case '1':
01321                if( ast_test_flag(&opts, OPT_PRIVACY) ) {
01322                   if (option_verbose > 2)
01323                      ast_verbose( VERBOSE_PREFIX_3 "--Set privacy database entry %s/%s to ALLOW\n",
01324                              opt_args[OPT_ARG_PRIVACY], privcid);
01325                   ast_privacy_set(opt_args[OPT_ARG_PRIVACY], privcid, AST_PRIVACY_ALLOW);
01326                }
01327                break;
01328             case '2':
01329                if( ast_test_flag(&opts, OPT_PRIVACY) ) {
01330                   if (option_verbose > 2)
01331                      ast_verbose( VERBOSE_PREFIX_3 "--Set privacy database entry %s/%s to DENY\n",
01332                              opt_args[OPT_ARG_PRIVACY], privcid);
01333                   ast_privacy_set(opt_args[OPT_ARG_PRIVACY], privcid, AST_PRIVACY_DENY);
01334                }
01335                strcpy(status,"NOANSWER");
01336                if (ast_test_flag(&opts, OPT_MUSICBACK)) {
01337                   ast_moh_stop(chan);
01338                } else if (ast_test_flag(&opts, OPT_RINGBACK)) {
01339                   ast_indicate(chan, -1);
01340                   sentringing=0;
01341                }
01342                res2 = ast_autoservice_stop(chan);
01343                ast_hangup(peer); /* hang up on the callee -- he didn't want to talk anyway! */
01344                res=0;
01345                goto out;
01346             case '3':
01347                if( ast_test_flag(&opts, OPT_PRIVACY) ) {
01348                   if (option_verbose > 2)
01349                      ast_verbose( VERBOSE_PREFIX_3 "--Set privacy database entry %s/%s to TORTURE\n",
01350                              opt_args[OPT_ARG_PRIVACY], privcid);
01351                   ast_privacy_set(opt_args[OPT_ARG_PRIVACY], privcid, AST_PRIVACY_TORTURE);
01352                }
01353                ast_copy_string(status, "TORTURE", sizeof(status));
01354                
01355                res = 0;
01356                if (ast_test_flag(&opts, OPT_MUSICBACK)) {
01357                   ast_moh_stop(chan);
01358                } else if (ast_test_flag(&opts, OPT_RINGBACK)) {
01359                   ast_indicate(chan, -1);
01360                   sentringing=0;
01361                }
01362                res2 = ast_autoservice_stop(chan);
01363                ast_hangup(peer); /* hang up on the caller -- he didn't want to talk anyway! */
01364                goto out; /* Is this right? */
01365             case '4':
01366                if( ast_test_flag(&opts, OPT_PRIVACY) ) {
01367                   if (option_verbose > 2)
01368                      ast_verbose( VERBOSE_PREFIX_3 "--Set privacy database entry %s/%s to KILL\n",
01369                              opt_args[OPT_ARG_PRIVACY], privcid);
01370                   ast_privacy_set(opt_args[OPT_ARG_PRIVACY], privcid, AST_PRIVACY_KILL);
01371                }
01372 
01373                ast_copy_string(status, "DONTCALL", sizeof(status));
01374                res = 0;
01375                if (ast_test_flag(&opts, OPT_MUSICBACK)) {
01376                   ast_moh_stop(chan);
01377                } else if (ast_test_flag(&opts, OPT_RINGBACK)) {
01378                   ast_indicate(chan, -1);
01379                   sentringing=0;
01380                }
01381                res2 = ast_autoservice_stop(chan);
01382                ast_hangup(peer); /* hang up on the caller -- he didn't want to talk anyway! */
01383                goto out; /* Is this right? */
01384             case '5':
01385                if( ast_test_flag(&opts, OPT_PRIVACY) ) {
01386                   if (option_verbose > 2)
01387                      ast_verbose( VERBOSE_PREFIX_3 "--Set privacy database entry %s/%s to ALLOW\n",
01388                              opt_args[OPT_ARG_PRIVACY], privcid);
01389                   ast_privacy_set(opt_args[OPT_ARG_PRIVACY], privcid, AST_PRIVACY_ALLOW);
01390                   if (ast_test_flag(&opts, OPT_MUSICBACK)) {
01391                      ast_moh_stop(chan);
01392                   } else if (ast_test_flag(&opts, OPT_RINGBACK)) {
01393                      ast_indicate(chan, -1);
01394                      sentringing=0;
01395                   }
01396                   res2 = ast_autoservice_stop(chan);
01397                   ast_hangup(peer); /* hang up on the caller -- he didn't want to talk anyway! */
01398                   res=0;
01399                   goto out;
01400                } /* if not privacy, then 5 is the same as "default" case */
01401             default:
01402                /* well, if the user messes up, ... he had his chance... What Is The Best Thing To Do?  */
01403                /* well, there seems basically two choices. Just patch the caller thru immediately,
01404                               or,... put 'em thru to voicemail. */
01405                /* since the callee may have hung up, let's do the voicemail thing, no database decision */
01406                if (option_verbose > 2)
01407                   ast_log(LOG_NOTICE,"privacy: no valid response from the callee. Sending the caller to voicemail, the callee isn't responding\n");
01408                if (ast_test_flag(&opts, OPT_MUSICBACK)) {
01409                   ast_moh_stop(chan);
01410                } else if (ast_test_flag(&opts, OPT_RINGBACK)) {
01411                   ast_indicate(chan, -1);
01412                   sentringing=0;
01413                }
01414                res2 = ast_autoservice_stop(chan);
01415                ast_hangup(peer); /* hang up on the callee -- he didn't want to talk anyway! */
01416                res=0;
01417                goto out;
01418             }
01419             if (ast_test_flag(&opts, OPT_MUSICBACK)) {
01420                ast_moh_stop(chan);
01421             } else if (ast_test_flag(&opts, OPT_RINGBACK)) {
01422                ast_indicate(chan, -1);
01423                sentringing=0;
01424             }
01425             res2 = ast_autoservice_stop(chan);
01426             /* if the intro is NOCALLERID, then there's no reason to leave it on disk, it'll 
01427                just clog things up, and it's not useful information, not being tied to a CID */
01428             if( strncmp(privcid,"NOCALLERID",10) == 0 || ast_test_flag(&opts, OPT_SCREEN_NOINTRO) ) {
01429                ast_filedelete(privintro, NULL);
01430                if( ast_fileexists(privintro,NULL,NULL ) > 0 )
01431                   ast_log(LOG_NOTICE,"privacy: ast_filedelete didn't do its job on %s\n", privintro);
01432                else if (option_verbose > 2)
01433                   ast_verbose( VERBOSE_PREFIX_3 "Successfully deleted %s intro file\n", privintro);
01434             }
01435          }
01436       }
01437       if (ast_test_flag(&opts, OPT_ANNOUNCE) && !ast_strlen_zero(opt_args[OPT_ARG_ANNOUNCE])) {
01438          /* Start autoservice on the other chan */
01439          res = ast_autoservice_start(chan);
01440          /* Now Stream the File */
01441          if (!res)
01442             res = ast_streamfile(peer, opt_args[OPT_ARG_ANNOUNCE], peer->language);
01443          if (!res) {
01444             digit = ast_waitstream(peer, AST_DIGIT_ANY); 
01445          }
01446          /* Ok, done. stop autoservice */
01447          res = ast_autoservice_stop(chan);
01448          if (digit > 0 && !res)
01449             res = ast_senddigit(chan, digit); 
01450          else
01451             res = digit;
01452 
01453       } else
01454          res = 0;
01455 
01456       if (chan && peer && ast_test_flag(&opts, OPT_GOTO) && !ast_strlen_zero(opt_args[OPT_ARG_GOTO])) {
01457          char *ch;
01458 
01459          for (ch = opt_args[OPT_ARG_GOTO]; *ch; ch++) {
01460             if (*ch == '^')
01461                *ch = '|';
01462          }
01463          ast_parseable_goto(chan, opt_args[OPT_ARG_GOTO]);
01464          ast_parseable_goto(peer, opt_args[OPT_ARG_GOTO]);
01465          peer->priority++;
01466          ast_pbx_start(peer);
01467          hanguptree(outgoing, NULL);
01468          LOCAL_USER_REMOVE(u);
01469          return 0;
01470       }
01471 
01472       if (ast_test_flag(&opts, OPT_CALLEE_MACRO) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_MACRO])) {
01473          char *ch;
01474 
01475          res = ast_autoservice_start(chan);
01476          if (res) {
01477             ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
01478             res = -1;
01479          }
01480 
01481          app = pbx_findapp("Macro");
01482 
01483          if (app && !res) {
01484             for (ch = opt_args[OPT_ARG_CALLEE_MACRO]; *ch; ch++) {
01485                if (*ch == '^')
01486                   *ch = '|';
01487             }
01488             res = pbx_exec(peer, app, opt_args[OPT_ARG_CALLEE_MACRO], 1);
01489             ast_log(LOG_DEBUG, "Macro exited with status %d\n", res);
01490             res = 0;
01491          } else {
01492             ast_log(LOG_ERROR, "Could not find application Macro\n");
01493             res = -1;
01494          }
01495 
01496          if (ast_autoservice_stop(chan) < 0) {
01497             ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
01498             res = -1;
01499          }
01500 
01501          if (!res) {
01502             if ((macro_result = pbx_builtin_getvar_helper(peer, "MACRO_RESULT"))) {
01503                if (!strcasecmp(macro_result, "BUSY")) {
01504                   ast_copy_string(status, macro_result, sizeof(status));
01505                   if (option_priority_jumping || ast_test_flag(&opts, OPT_PRIORITY_JUMP)) {
01506                      if (!ast_goto_if_exists(chan, NULL, NULL, chan->priority + 101)) {
01507                         ast_set_flag(peerflags, OPT_GO_ON);
01508                      }
01509                   } else
01510                      ast_set_flag(peerflags, OPT_GO_ON);
01511                   res = -1;
01512                }
01513                else if (!strcasecmp(macro_result, "CONGESTION") || !strcasecmp(macro_result, "CHANUNAVAIL")) {
01514                   ast_copy_string(status, macro_result, sizeof(status));
01515                   ast_set_flag(peerflags, OPT_GO_ON); 
01516                   res = -1;
01517                }
01518                else if (!strcasecmp(macro_result, "CONTINUE")) {
01519                   /* hangup peer and keep chan alive assuming the macro has changed 
01520                      the context / exten / priority or perhaps 
01521                      the next priority in the current exten is desired.
01522                   */
01523                   ast_set_flag(peerflags, OPT_GO_ON); 
01524                   res = -1;
01525                } else if (!strcasecmp(macro_result, "ABORT")) {
01526                   /* Hangup both ends unless the caller has the g flag */
01527                   res = -1;
01528                } else if (!strncasecmp(macro_result, "GOTO:",5) && (macro_transfer_dest = ast_strdupa(macro_result + 5))) {
01529                   res = -1;
01530                   /* perform a transfer to a new extension */
01531                   if (strchr(macro_transfer_dest,'^')) { /* context^exten^priority*/
01532                      /* no brainer mode... substitute ^ with | and feed it to builtin goto */
01533                      for (res=0;res<strlen(macro_transfer_dest);res++)
01534                         if (macro_transfer_dest[res] == '^')
01535                            macro_transfer_dest[res] = '|';
01536 
01537                      if (!ast_parseable_goto(chan, macro_transfer_dest))
01538                         ast_set_flag(peerflags, OPT_GO_ON);
01539 
01540                   }
01541                }
01542             }
01543          }
01544       }
01545 
01546       if (!res) {
01547          if (calldurationlimit > 0) {
01548             time_t now;
01549 
01550             time(&now);
01551             chan->whentohangup = now + calldurationlimit;
01552          }
01553          if (!ast_strlen_zero(dtmfcalled)) { 
01554             if (option_verbose > 2)
01555                ast_verbose(VERBOSE_PREFIX_3 "Sending DTMF '%s' to the called party.\n",dtmfcalled);
01556             res = ast_dtmf_stream(peer,chan,dtmfcalled,250);
01557          }
01558          if (!ast_strlen_zero(dtmfcalling)) {
01559             if (option_verbose > 2)
01560                ast_verbose(VERBOSE_PREFIX_3 "Sending DTMF '%s' to the calling party.\n",dtmfcalling);
01561             res = ast_dtmf_stream(chan,peer,dtmfcalling,250);
01562          }
01563       }
01564       
01565       if (!res) {
01566          memset(&config,0,sizeof(struct ast_bridge_config));
01567          if (play_to_caller)
01568             ast_set_flag(&(config.features_caller), AST_FEATURE_PLAY_WARNING);
01569          if (play_to_callee)
01570             ast_set_flag(&(config.features_callee), AST_FEATURE_PLAY_WARNING);
01571          if (ast_test_flag(peerflags, OPT_CALLEE_TRANSFER))
01572             ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
01573          if (ast_test_flag(peerflags, OPT_CALLER_TRANSFER))
01574             ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
01575          if (ast_test_flag(peerflags, OPT_CALLEE_HANGUP))
01576             ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
01577          if (ast_test_flag(peerflags, OPT_CALLER_HANGUP))
01578             ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
01579          if (ast_test_flag(peerflags, OPT_CALLEE_MONITOR))
01580             ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
01581          if (ast_test_flag(peerflags, OPT_CALLER_MONITOR)) 
01582             ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
01583 
01584          config.timelimit = timelimit;
01585          config.play_warning = play_warning;
01586          config.warning_freq = warning_freq;
01587          config.warning_sound = warning_sound;
01588          config.end_sound = end_sound;
01589          config.start_sound = start_sound;
01590          if (moh) {
01591             moh = 0;
01592             ast_moh_stop(chan);
01593          } else if (sentringing) {
01594             sentringing = 0;
01595             ast_indicate(chan, -1);
01596          }
01597          /* Be sure no generators are left on it */
01598          ast_deactivate_generator(chan);
01599          /* Make sure channels are compatible */
01600          res = ast_channel_make_compatible(chan, peer);
01601          if (res < 0) {
01602             ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", chan->name, peer->name);
01603             ast_hangup(peer);
01604             LOCAL_USER_REMOVE(u);
01605             return -1;
01606          }
01607          res = ast_bridge_call(chan,peer,&config);
01608          time(&end_time);
01609          snprintf(toast, sizeof(toast), "%ld", (long)(end_time - answer_time));
01610          pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", toast);
01611          
01612       } else {
01613          time(&end_time);
01614          res = -1;
01615       }
01616       snprintf(toast, sizeof(toast), "%ld", (long)(end_time - start_time));
01617       pbx_builtin_setvar_helper(chan, "DIALEDTIME", toast);
01618       
01619       if (res != AST_PBX_NO_HANGUP_PEER) {
01620          if (!chan->_softhangup)
01621             chan->hangupcause = peer->hangupcause;
01622          ast_hangup(peer);
01623       }
01624    }  
01625 out:
01626    if (moh) {
01627       moh = 0;
01628       ast_moh_stop(chan);
01629    } else if (sentringing) {
01630       sentringing = 0;
01631       ast_indicate(chan, -1);
01632    }
01633    hanguptree(outgoing, NULL);
01634    pbx_builtin_setvar_helper(chan, "DIALSTATUS", status);
01635    ast_log(LOG_DEBUG, "Exiting with DIALSTATUS=%s.\n", status);
01636    
01637    if ((ast_test_flag(peerflags, OPT_GO_ON)) && (!chan->_softhangup) && (res != AST_PBX_KEEPALIVE))
01638       res=0;
01639    
01640    LOCAL_USER_REMOVE(u);    
01641    
01642    return res;
01643 }
01644 
01645 static int dial_exec(struct ast_channel *chan, void *data)
01646 {
01647    struct ast_flags peerflags;
01648    memset(&peerflags, 0, sizeof(peerflags));
01649    return dial_exec_full(chan, data, &peerflags);
01650 }
01651 
01652 static int retrydial_exec(struct ast_channel *chan, void *data)
01653 {
01654    char *announce = NULL, *context = NULL, *dialdata = NULL;
01655    int sleep = 0, loops = 0, res = 0;
01656    struct localuser *u;
01657    struct ast_flags peerflags;
01658    
01659    if (ast_strlen_zero(data)) {
01660       ast_log(LOG_WARNING, "RetryDial requires an argument!\n");
01661       return -1;
01662    }  
01663 
01664    LOCAL_USER_ADD(u);
01665 
01666    announce = ast_strdupa(data); 
01667    if (!announce) {  
01668       ast_log(LOG_ERROR, "Out of memory!\n");
01669       LOCAL_USER_REMOVE(u);
01670       return -1;
01671    }
01672    
01673    memset(&peerflags, 0, sizeof(peerflags));
01674 
01675    if ((dialdata = strchr(announce, '|'))) {
01676       *dialdata = '\0';
01677       dialdata++;
01678       if ((sleep = atoi(dialdata))) {
01679          sleep *= 1000;
01680       } else {
01681          ast_log(LOG_ERROR, "%s requires the numerical argument <sleep>\n",rapp);
01682          LOCAL_USER_REMOVE(u);
01683          return -1;
01684       }
01685       if ((dialdata = strchr(dialdata, '|'))) {
01686          *dialdata = '\0';
01687          dialdata++;
01688          if (!(loops = atoi(dialdata))) {
01689             ast_log(LOG_ERROR, "%s requires the numerical argument <loops>\n",rapp);
01690             LOCAL_USER_REMOVE(u);
01691             return -1;
01692          }
01693       }
01694    }
01695    
01696    if ((dialdata = strchr(dialdata, '|'))) {
01697       *dialdata = '\0';
01698       dialdata++;
01699    } else {
01700       ast_log(LOG_ERROR, "%s requires more arguments\n",rapp);
01701       LOCAL_USER_REMOVE(u);
01702       return -1;
01703    }
01704       
01705    if (sleep < 1000)
01706       sleep = 10000;
01707    
01708    if (!loops)
01709       loops = -1;
01710    
01711    context = pbx_builtin_getvar_helper(chan, "EXITCONTEXT");
01712    
01713    while (loops) {
01714       chan->data = "Retrying";
01715       if (ast_test_flag(chan, AST_FLAG_MOH))
01716          ast_moh_stop(chan);
01717 
01718       if ((res = dial_exec_full(chan, dialdata, &peerflags)) == 0) {
01719          if (ast_test_flag(&peerflags, OPT_DTMF_EXIT)) {
01720             if (!(res = ast_streamfile(chan, announce, chan->language)))
01721                res = ast_waitstream(chan, AST_DIGIT_ANY);
01722             if (!res && sleep) {
01723                if (!ast_test_flag(chan, AST_FLAG_MOH))
01724                   ast_moh_start(chan, NULL);
01725                res = ast_waitfordigit(chan, sleep);
01726             }
01727          } else {
01728             if (!(res = ast_streamfile(chan, announce, chan->language)))
01729                res = ast_waitstream(chan, "");
01730             if (sleep) {
01731                if (!ast_test_flag(chan, AST_FLAG_MOH))
01732                   ast_moh_start(chan, NULL);
01733                if (!res) 
01734                   res = ast_waitfordigit(chan, sleep);
01735             }
01736          }
01737       }
01738 
01739       if (res < 0)
01740          break;
01741       else if (res > 0) { /* Trying to send the call elsewhere (1 digit ext) */
01742          if (onedigit_goto(chan, context, (char) res, 1)) {
01743             res = 0;
01744             break;
01745          }
01746       }
01747       loops--;
01748    }
01749    
01750    if (ast_test_flag(chan, AST_FLAG_MOH))
01751       ast_moh_stop(chan);
01752 
01753    LOCAL_USER_REMOVE(u);
01754    return loops ? res : 0;
01755 
01756 }
01757 
01758 int unload_module(void)
01759 {
01760    int res;
01761 
01762    res = ast_unregister_application(app);
01763    res |= ast_unregister_application(rapp);
01764 
01765    STANDARD_HANGUP_LOCALUSERS;
01766    
01767    return res;
01768 }
01769 
01770 int load_module(void)
01771 {
01772    int res;
01773 
01774    res = ast_register_application(app, dial_exec, synopsis, descrip);
01775    res |= ast_register_application(rapp, retrydial_exec, rsynopsis, rdescrip);
01776    
01777    return res;
01778 }
01779 
01780 char *description(void)
01781 {
01782    return tdesc;
01783 }
01784 
01785 int usecount(void)
01786 {
01787    int res;
01788    STANDARD_USECOUNT(res);
01789    return res;
01790 }
01791 
01792 char *key()
01793 {
01794    return ASTERISK_GPL_KEY;
01795 }

Generated on Thu May 24 14:21:05 2007 for Asterisk - the Open Source PBX by  doxygen 1.4.7