Mon Mar 20 08:20:06 2006

Asterisk developer's documentation


Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

app_dial.c

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

Generated on Mon Mar 20 08:20:06 2006 for Asterisk - the Open Source PBX by  doxygen 1.3.9.1