Mon Nov 24 15:33:56 2008

Asterisk developer's documentation


app_dial.c

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

Generated on Mon Nov 24 15:33:56 2008 for Asterisk - the Open Source PBX by  doxygen 1.4.7