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

Generated on Sun Aug 6 15:02:23 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.2