Sat Oct 11 06:49:52 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  * \ingroup applications
00024  */
00025 
00026 #include <stdlib.h>
00027 #include <errno.h>
00028 #include <unistd.h>
00029 #include <string.h>
00030 #include <stdlib.h>
00031 #include <stdio.h>
00032 #include <sys/time.h>
00033 #include <sys/signal.h>
00034 #include <sys/stat.h>
00035 #include <netinet/in.h>
00036 
00037 #include "asterisk.h"
00038 
00039 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 73052 $")
00040 
00041 #include "asterisk/lock.h"
00042 #include "asterisk/file.h"
00043 #include "asterisk/logger.h"
00044 #include "asterisk/channel.h"
00045 #include "asterisk/pbx.h"
00046 #include "asterisk/options.h"
00047 #include "asterisk/module.h"
00048 #include "asterisk/translate.h"
00049 #include "asterisk/say.h"
00050 #include "asterisk/config.h"
00051 #include "asterisk/features.h"
00052 #include "asterisk/musiconhold.h"
00053 #include "asterisk/callerid.h"
00054 #include "asterisk/utils.h"
00055 #include "asterisk/app.h"
00056 #include "asterisk/causes.h"
00057 #include "asterisk/manager.h"
00058 #include "asterisk/privacy.h"
00059 
00060 static char *tdesc = "Dialing Application";
00061 
00062 static char *app = "Dial";
00063 
00064 static char *synopsis = "Place a call and connect to the current channel";
00065 
00066 static char *descrip =
00067 "  Dial(Technology/resource[&Tech2/resource2...][|timeout][|options][|URL]):\n"
00068 "This application will place calls to one or more specified channels. As soon\n"
00069 "as one of the requested channels answers, the originating channel will be\n"
00070 "answered, if it has not already been answered. These two channels will then\n"
00071 "be active in a bridged call. All other channels that were requested will then\n"
00072 "be hung up.\n"
00073 "  Unless there is a timeout specified, the Dial application will wait\n"
00074 "indefinitely until one of the called channels answers, the user hangs up, or\n"
00075 "if all of the called channels are busy or unavailable. Dialplan executing will\n"
00076 "continue if no requested channels can be called, or if the timeout expires.\n\n"
00077 "  This application sets the following channel variables upon completion:\n"
00078 "    DIALEDTIME   - This is the time from dialing a channel until when it\n"
00079 "                   is disconnected.\n" 
00080 "    ANSWEREDTIME - This is the amount of time for actual call.\n"
00081 "    DIALSTATUS   - This is the status of the call:\n"
00082 "                   CHANUNAVAIL | CONGESTION | NOANSWER | BUSY | ANSWER | CANCEL\n" 
00083 "                   DONTCALL | TORTURE | INVALIDARGS\n"
00084 "  For the Privacy and Screening Modes, the DIALSTATUS variable will be set to\n"
00085 "DONTCALL if the called party chooses to send the calling party to the 'Go Away'\n"
00086 "script. The DIALSTATUS variable will be set to TORTURE if the called party\n"
00087 "wants to send the caller to the 'torture' script.\n"
00088 "  This application will report normal termination if the originating channel\n"
00089 "hangs up, or if the call is bridged and either of the parties in the bridge\n"
00090 "ends the call.\n"
00091 "  The optional URL will be sent to the called party if the channel supports it.\n"
00092 "  If the OUTBOUND_GROUP variable is set, all peer channels created by this\n"
00093 "application will be put into that group (as in Set(GROUP()=...).\n"
00094 "  If the OUTBOUND_GROUP_ONCE variable is set, all peer channels created by this\n"
00095 "application will be put into that group (as in Set(GROUP()=...). Unlike OUTBOUND_GROUP,\n"
00096 "however, the variable will be unset after use.\n\n"
00097 "  Options:\n"
00098 "    A(x) - Play an announcement to the called party, using 'x' as the file.\n"
00099 "    C    - Reset the CDR for this call.\n"
00100 "    d    - Allow the calling user to dial a 1 digit extension while waiting for\n"
00101 "           a call to be answered. Exit to that extension if it exists in the\n"
00102 "           current context, or the context defined in the EXITCONTEXT variable,\n"
00103 "           if it exists.\n"
00104 "    D([called][:calling]) - Send the specified DTMF strings *after* the called\n"
00105 "           party has answered, but before the call gets bridged. The 'called'\n"
00106 "           DTMF string is sent to the called party, and the 'calling' DTMF\n"
00107 "           string is sent to the calling party. Both parameters can be used\n"
00108 "           alone.\n"   
00109 "    f    - Force the callerid of the *calling* channel to be set as the\n"
00110 "           extension associated with the channel using a dialplan 'hint'.\n"
00111 "           For example, some PSTNs do not allow CallerID to be set to anything\n"
00112 "           other than the number assigned to the caller.\n"
00113 "    g    - Proceed with dialplan execution at the current extension if the\n"
00114 "           destination channel hangs up.\n"
00115 "    G(context^exten^pri) - If the call is answered, transfer the calling party to\n"
00116 "           the specified priority and the called party to the specified priority+1.\n"
00117 "           Optionally, an extension, or extension and context may be specified. \n"
00118 "           Otherwise, the current extension is used. You cannot use any additional\n"
00119 "           action post answer options in conjunction with this option.\n" 
00120 "    h    - Allow the called party to hang up by sending the '*' DTMF digit.\n"
00121 "    H    - Allow the calling party to hang up by hitting the '*' DTMF digit.\n"
00122 "    j    - Jump to priority n+101 if all of the requested channels were busy.\n"
00123 "    L(x[:y][:z]) - Limit the call to 'x' ms. Play a warning when 'y' ms are\n"
00124 "           left. Repeat the warning every 'z' ms. The following special\n"
00125 "           variables can be used with this option:\n"
00126 "           * LIMIT_PLAYAUDIO_CALLER   yes|no (default yes)\n"
00127 "                                      Play sounds to the caller.\n"
00128 "           * LIMIT_PLAYAUDIO_CALLEE   yes|no\n"
00129 "                                      Play sounds to the callee.\n"
00130 "           * LIMIT_TIMEOUT_FILE       File to play when time is up.\n"
00131 "           * LIMIT_CONNECT_FILE       File to play when call begins.\n"
00132 "           * LIMIT_WARNING_FILE       File to play as warning if 'y' is defined.\n"
00133 "                                      The default is to say the time remaining.\n"
00134 "    m([class]) - Provide hold music to the calling party until a requested\n"
00135 "           channel answers. A specific MusicOnHold class can be\n"
00136 "           specified.\n"
00137 "    M(x[^arg]) - Execute the Macro for the *called* channel before connecting\n"
00138 "           to the calling channel. Arguments can be specified to the Macro\n"
00139 "           using '^' as a delimeter. The Macro can set the variable\n"
00140 "           MACRO_RESULT to specify the following actions after the Macro is\n" 
00141 "           finished executing.\n"
00142 "           * ABORT        Hangup both legs of the call.\n"
00143 "           * CONGESTION   Behave as if line congestion was encountered.\n"
00144 "           * BUSY         Behave as if a busy signal was encountered. This will also\n"
00145 "                          have the application jump to priority n+101 if the\n"
00146 "                          'j' option is set.\n"
00147 "           * CONTINUE     Hangup the called party and allow the calling party\n"
00148 "                          to continue dialplan execution at the next priority.\n"
00149 "           * GOTO:<context>^<exten>^<priority> - Transfer the call to the\n"
00150 "                          specified priority. Optionally, an extension, or\n"
00151 "                          extension and priority can be specified.\n"
00152 "           You cannot use any additional action post answer options in conjunction\n"
00153 "           with this option.\n"
00154 "    n    - This option is a modifier for the screen/privacy mode. It specifies\n"
00155 "           that no introductions are to be saved in the priv-callerintros\n"
00156 "           directory.\n"
00157 "    N    - This option is a modifier for the screen/privacy mode. It specifies\n"
00158 "           that if callerID is present, do not screen the call.\n"
00159 "    o    - Specify that the CallerID that was present on the *calling* channel\n"
00160 "           be set as the CallerID on the *called* channel. This was the\n"
00161 "           behavior of Asterisk 1.0 and earlier.\n"
00162 "    p    - This option enables screening mode. This is basically Privacy mode\n"
00163 "           without memory.\n"
00164 "    P([x]) - Enable privacy mode. Use 'x' as the family/key in the database if\n"
00165 "           it is provided. The current extension is used if a database\n"
00166 "           family/key is not specified.\n"
00167 "    r    - Indicate ringing to the calling party. Pass no audio to the calling\n"
00168 "           party until the called channel has answered.\n"
00169 "    S(x) - Hang up the call after 'x' seconds *after* the called party has\n"
00170 "           answered the call.\n"   
00171 "    t    - Allow the called party to transfer the calling party by sending the\n"
00172 "           DTMF sequence defined in features.conf.\n"
00173 "    T    - Allow the calling party to transfer the called party by sending the\n"
00174 "           DTMF sequence defined in features.conf.\n"
00175 "    w    - Allow the called party to enable recording of the call by sending\n"
00176 "           the DTMF sequence defined for one-touch recording in features.conf.\n"
00177 "    W    - Allow the calling party to enable recording of the call by sending\n"
00178 "           the DTMF sequence defined for one-touch recording in features.conf.\n";
00179 
00180 /* RetryDial App by Anthony Minessale II <anthmct@yahoo.com> Jan/2005 */
00181 static char *rapp = "RetryDial";
00182 static char *rsynopsis = "Place a call, retrying on failure allowing optional exit extension.";
00183 static char *rdescrip =
00184 "  RetryDial(announce|sleep|retries|dialargs): This application will attempt to\n"
00185 "place a call using the normal Dial application. If no channel can be reached,\n"
00186 "the 'announce' file will be played. Then, it will wait 'sleep' number of\n"
00187 "seconds before retying the call. After 'retires' number of attempts, the\n"
00188 "calling channel will continue at the next priority in the dialplan. If the\n"
00189 "'retries' setting is set to 0, this application will retry endlessly.\n"
00190 "  While waiting to retry a call, a 1 digit extension may be dialed. If that\n"
00191 "extension exists in either the context defined in ${EXITCONTEXT} or the current\n"
00192 "one, The call will jump to that extension immediately.\n"
00193 "  The 'dialargs' are specified in the same format that arguments are provided\n"
00194 "to the Dial application.\n";
00195 
00196 enum {
00197    OPT_ANNOUNCE = (1 << 0),
00198    OPT_RESETCDR = (1 << 1),
00199    OPT_DTMF_EXIT = (1 << 2),
00200    OPT_SENDDTMF = (1 << 3),
00201    OPT_FORCECLID = (1 << 4),
00202    OPT_GO_ON = (1 << 5),
00203    OPT_CALLEE_HANGUP = (1 << 6),
00204    OPT_CALLER_HANGUP = (1 << 7),
00205    OPT_PRIORITY_JUMP = (1 << 8),
00206    OPT_DURATION_LIMIT = (1 << 9),
00207    OPT_MUSICBACK = (1 << 10),
00208    OPT_CALLEE_MACRO = (1 << 11),
00209    OPT_SCREEN_NOINTRO = (1 << 12),
00210    OPT_SCREEN_NOCLID = (1 << 13),
00211    OPT_ORIGINAL_CLID = (1 << 14),
00212    OPT_SCREENING = (1 << 15),
00213    OPT_PRIVACY = (1 << 16),
00214    OPT_RINGBACK = (1 << 17),
00215    OPT_DURATION_STOP = (1 << 18),
00216    OPT_CALLEE_TRANSFER = (1 << 19),
00217    OPT_CALLER_TRANSFER = (1 << 20),
00218    OPT_CALLEE_MONITOR = (1 << 21),
00219    OPT_CALLER_MONITOR = (1 << 22),
00220    OPT_GOTO = (1 << 23),
00221 } dial_exec_option_flags;
00222 
00223 #define DIAL_STILLGOING       (1 << 30)
00224 #define DIAL_NOFORWARDHTML    (1 << 31)
00225 
00226 enum {
00227    OPT_ARG_ANNOUNCE = 0,
00228    OPT_ARG_SENDDTMF,
00229    OPT_ARG_GOTO,
00230    OPT_ARG_DURATION_LIMIT,
00231    OPT_ARG_MUSICBACK,
00232    OPT_ARG_CALLEE_MACRO,
00233    OPT_ARG_PRIVACY,
00234    OPT_ARG_DURATION_STOP,
00235    /* note: this entry _MUST_ be the last one in the enum */
00236    OPT_ARG_ARRAY_SIZE,
00237 } dial_exec_option_args;
00238 
00239 AST_APP_OPTIONS(dial_exec_options, {
00240    AST_APP_OPTION_ARG('A', OPT_ANNOUNCE, OPT_ARG_ANNOUNCE),
00241    AST_APP_OPTION('C', OPT_RESETCDR),
00242    AST_APP_OPTION('d', OPT_DTMF_EXIT),
00243    AST_APP_OPTION_ARG('D', OPT_SENDDTMF, OPT_ARG_SENDDTMF),
00244    AST_APP_OPTION('f', OPT_FORCECLID),
00245    AST_APP_OPTION('g', OPT_GO_ON),
00246    AST_APP_OPTION_ARG('G', OPT_GOTO, OPT_ARG_GOTO),
00247    AST_APP_OPTION('h', OPT_CALLEE_HANGUP),
00248    AST_APP_OPTION('H', OPT_CALLER_HANGUP),
00249    AST_APP_OPTION('j', OPT_PRIORITY_JUMP),
00250    AST_APP_OPTION_ARG('L', OPT_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT),
00251    AST_APP_OPTION_ARG('m', OPT_MUSICBACK, OPT_ARG_MUSICBACK),
00252    AST_APP_OPTION_ARG('M', OPT_CALLEE_MACRO, OPT_ARG_CALLEE_MACRO),
00253    AST_APP_OPTION('n', OPT_SCREEN_NOINTRO),
00254    AST_APP_OPTION('N', OPT_SCREEN_NOCLID),
00255    AST_APP_OPTION('o', OPT_ORIGINAL_CLID),
00256    AST_APP_OPTION('p', OPT_SCREENING),
00257    AST_APP_OPTION_ARG('P', OPT_PRIVACY, OPT_ARG_PRIVACY),
00258    AST_APP_OPTION('r', OPT_RINGBACK),
00259    AST_APP_OPTION_ARG('S', OPT_DURATION_STOP, OPT_ARG_DURATION_STOP),
00260    AST_APP_OPTION('t', OPT_CALLEE_TRANSFER),
00261    AST_APP_OPTION('T', OPT_CALLER_TRANSFER),
00262    AST_APP_OPTION('w', OPT_CALLEE_MONITOR),
00263    AST_APP_OPTION('W', OPT_CALLER_MONITOR),
00264 });
00265 
00266 /* We define a custom "local user" structure because we
00267    use it not only for keeping track of what is in use but
00268    also for keeping track of who we're dialing. */
00269 
00270 struct localuser {
00271    struct ast_channel *chan;
00272    unsigned int flags;
00273    int forwards;
00274    struct localuser *next;
00275 };
00276 
00277 LOCAL_USER_DECL;
00278 
00279 static void hanguptree(struct localuser *outgoing, struct ast_channel *exception)
00280 {
00281    /* Hang up a tree of stuff */
00282    struct localuser *oo;
00283    while (outgoing) {
00284       /* Hangup any existing lines we have open */
00285       if (outgoing->chan && (outgoing->chan != exception))
00286          ast_hangup(outgoing->chan);
00287       oo = outgoing;
00288       outgoing=outgoing->next;
00289       free(oo);
00290    }
00291 }
00292 
00293 #define AST_MAX_FORWARDS   8
00294 
00295 #define AST_MAX_WATCHERS 256
00296 
00297 #define HANDLE_CAUSE(cause, chan) do { \
00298    switch(cause) { \
00299    case AST_CAUSE_BUSY: \
00300       if (chan->cdr) \
00301          ast_cdr_busy(chan->cdr); \
00302       numbusy++; \
00303       break; \
00304    case AST_CAUSE_CONGESTION: \
00305       if (chan->cdr) \
00306          ast_cdr_failed(chan->cdr); \
00307       numcongestion++; \
00308       break; \
00309    case AST_CAUSE_UNREGISTERED: \
00310       if (chan->cdr) \
00311          ast_cdr_failed(chan->cdr); \
00312       numnochan++; \
00313       break; \
00314    case AST_CAUSE_NORMAL_CLEARING: \
00315       break; \
00316    default: \
00317       numnochan++; \
00318       break; \
00319    } \
00320 } while (0)
00321 
00322 
00323 static int onedigit_goto(struct ast_channel *chan, char *context, char exten, int pri) 
00324 {
00325    char rexten[2] = { exten, '\0' };
00326 
00327    if (context) {
00328       if (!ast_goto_if_exists(chan, context, rexten, pri))
00329          return 1;
00330    } else {
00331       if (!ast_goto_if_exists(chan, chan->context, rexten, pri))
00332          return 1;
00333       else if (!ast_strlen_zero(chan->macrocontext)) {
00334          if (!ast_goto_if_exists(chan, chan->macrocontext, rexten, pri))
00335             return 1;
00336       }
00337    }
00338    return 0;
00339 }
00340 
00341 
00342 static char *get_cid_name(char *name, int namelen, struct ast_channel *chan)
00343 {
00344    char *context;
00345    char *exten;
00346    if (!ast_strlen_zero(chan->macrocontext))
00347       context = chan->macrocontext;
00348    else
00349       context = chan->context;
00350 
00351    if (!ast_strlen_zero(chan->macroexten))
00352       exten = chan->macroexten;
00353    else
00354       exten = chan->exten;
00355 
00356    if (ast_get_hint(NULL, 0, name, namelen, chan, context, exten))
00357       return name;
00358    else
00359       return "";
00360 }
00361 
00362 static void senddialevent(struct ast_channel *src, struct ast_channel *dst)
00363 {
00364    manager_event(EVENT_FLAG_CALL, "Dial", 
00365             "Source: %s\r\n"
00366             "Destination: %s\r\n"
00367             "CallerID: %s\r\n"
00368             "CallerIDName: %s\r\n"
00369             "SrcUniqueID: %s\r\n"
00370             "DestUniqueID: %s\r\n",
00371             src->name, dst->name, src->cid.cid_num ? src->cid.cid_num : "<unknown>",
00372             src->cid.cid_name ? src->cid.cid_name : "<unknown>", src->uniqueid,
00373             dst->uniqueid);
00374 }
00375 
00376 static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localuser *outgoing, int *to, struct ast_flags *peerflags, int *sentringing, char *status, size_t statussize, int busystart, int nochanstart, int congestionstart, int priority_jump, int *result)
00377 {
00378    struct localuser *o;
00379    int found;
00380    int numlines;
00381    int numbusy = busystart;
00382    int numcongestion = congestionstart;
00383    int numnochan = nochanstart;
00384    int prestart = busystart + congestionstart + nochanstart;
00385    int cause;
00386    int orig = *to;
00387    struct ast_frame *f;
00388    struct ast_channel *peer = NULL;
00389    struct ast_channel *watchers[AST_MAX_WATCHERS];
00390    int pos;
00391    int single;
00392    struct ast_channel *winner;
00393    char *context = NULL;
00394    char cidname[AST_MAX_EXTENSION];
00395 
00396    single = (outgoing && !outgoing->next && !ast_test_flag(outgoing, OPT_MUSICBACK | OPT_RINGBACK));
00397    
00398    if (single) {
00399       /* Turn off hold music, etc */
00400       ast_deactivate_generator(in);
00401       /* If we are calling a single channel, make them compatible for in-band tone purpose */
00402       ast_channel_make_compatible(outgoing->chan, in);
00403    }
00404    
00405    
00406    while (*to && !peer) {
00407       o = outgoing;
00408       found = -1;
00409       pos = 1;
00410       numlines = prestart;
00411       watchers[0] = in;
00412       while (o) {
00413          /* Keep track of important channels */
00414          if (ast_test_flag(o, DIAL_STILLGOING) && o->chan) {
00415             watchers[pos++] = o->chan;
00416             found = 1;
00417          }
00418          o = o->next;
00419          numlines++;
00420       }
00421       if (found < 0) {
00422          if (numlines == (numbusy + numcongestion + numnochan)) {
00423             if (option_verbose > 2)
00424                ast_verbose( VERBOSE_PREFIX_2 "Everyone is busy/congested at this time (%d:%d/%d/%d)\n", numlines, numbusy, numcongestion, numnochan);
00425             if (numbusy)
00426                strcpy(status, "BUSY"); 
00427             else if (numcongestion)
00428                strcpy(status, "CONGESTION");
00429             else if (numnochan)
00430                strcpy(status, "CHANUNAVAIL");
00431             if (option_priority_jumping || priority_jump)
00432                ast_goto_if_exists(in, in->context, in->exten, in->priority + 101);
00433          } else {
00434             if (option_verbose > 2)
00435                ast_verbose( VERBOSE_PREFIX_2 "No one is available to answer at this time (%d:%d/%d/%d)\n", numlines, numbusy, numcongestion, numnochan);
00436          }
00437          *to = 0;
00438          return NULL;
00439       }
00440       winner = ast_waitfor_n(watchers, pos, to);
00441       o = outgoing;
00442       while (o) {
00443          if (ast_test_flag(o, DIAL_STILLGOING) && o->chan && (o->chan->_state == AST_STATE_UP)) {
00444             if (!peer) {
00445                if (option_verbose > 2)
00446                   ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
00447                peer = o->chan;
00448                ast_copy_flags(peerflags, o,
00449                          OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
00450                          OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
00451                          OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
00452                          DIAL_NOFORWARDHTML);
00453             }
00454          } else if (o->chan && (o->chan == winner)) {
00455             if (!ast_strlen_zero(o->chan->call_forward)) {
00456                char tmpchan[256];
00457                char *stuff;
00458                char *tech;
00459                ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
00460                if ((stuff = strchr(tmpchan, '/'))) {
00461                   *stuff = '\0';
00462                   stuff++;
00463                   tech = tmpchan;
00464                } else {
00465                   snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
00466                   stuff = tmpchan;
00467                   tech = "Local";
00468                }
00469                /* Before processing channel, go ahead and check for forwarding */
00470                o->forwards++;
00471                if (o->forwards < AST_MAX_FORWARDS) {
00472                   if (option_verbose > 2)
00473                      ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
00474                   /* Setup parameters */
00475                   o->chan = ast_request(tech, in->nativeformats, stuff, &cause);
00476                   if (o->chan) {
00477                      if (single)
00478                         ast_channel_make_compatible(o->chan, in);
00479                      ast_channel_inherit_variables(in, o->chan);
00480                   } else
00481                      ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
00482                } else {
00483                   if (option_verbose > 2)
00484                      ast_verbose(VERBOSE_PREFIX_3 "Too many forwards from %s\n", o->chan->name);
00485                   cause = AST_CAUSE_CONGESTION;
00486                   o->chan = NULL;
00487                }
00488                if (!o->chan) {
00489                   ast_clear_flag(o, DIAL_STILLGOING); 
00490                   HANDLE_CAUSE(cause, in);
00491                } else {
00492                   if (o->chan->cid.cid_num)
00493                      free(o->chan->cid.cid_num);
00494                   o->chan->cid.cid_num = NULL;
00495                   if (o->chan->cid.cid_name)
00496                      free(o->chan->cid.cid_name);
00497                   o->chan->cid.cid_name = NULL;
00498 
00499                   if (ast_test_flag(o, OPT_FORCECLID)) {
00500                      char *newcid = NULL;
00501 
00502                      if (!ast_strlen_zero(in->macroexten))
00503                         newcid = in->macroexten;
00504                      else
00505                         newcid = in->exten;
00506                      o->chan->cid.cid_num = strdup(newcid);
00507                      ast_copy_string(o->chan->accountcode, winner->accountcode, sizeof(o->chan->accountcode));
00508                      o->chan->cdrflags = winner->cdrflags;
00509                      if (!o->chan->cid.cid_num)
00510                         ast_log(LOG_WARNING, "Out of memory\n");
00511                   } else {
00512                      if (in->cid.cid_num) {
00513                         o->chan->cid.cid_num = strdup(in->cid.cid_num);
00514                         if (!o->chan->cid.cid_num)
00515                            ast_log(LOG_WARNING, "Out of memory\n");  
00516                      }
00517                      if (in->cid.cid_name) {
00518                         o->chan->cid.cid_name = strdup(in->cid.cid_name);
00519                         if (!o->chan->cid.cid_name)
00520                            ast_log(LOG_WARNING, "Out of memory\n");  
00521                      }
00522                      ast_copy_string(o->chan->accountcode, in->accountcode, sizeof(o->chan->accountcode));
00523                      o->chan->cdrflags = in->cdrflags;
00524                   }
00525 
00526                   if (in->cid.cid_ani) {
00527                      if (o->chan->cid.cid_ani)
00528                         free(o->chan->cid.cid_ani);
00529                      o->chan->cid.cid_ani = strdup(in->cid.cid_ani);
00530                      if (!o->chan->cid.cid_ani)
00531                         ast_log(LOG_WARNING, "Out of memory\n");
00532                   }
00533                   if (o->chan->cid.cid_rdnis) 
00534                      free(o->chan->cid.cid_rdnis);
00535                   if (!ast_strlen_zero(in->macroexten))
00536                      o->chan->cid.cid_rdnis = strdup(in->macroexten);
00537                   else
00538                      o->chan->cid.cid_rdnis = strdup(in->exten);
00539                   if (ast_call(o->chan, tmpchan, 0)) {
00540                      ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
00541                      ast_clear_flag(o, DIAL_STILLGOING); 
00542                      ast_hangup(o->chan);
00543                      o->chan = NULL;
00544                      numnochan++;
00545                   } else {
00546                      senddialevent(in, o->chan);
00547                      /* After calling, set callerid to extension */
00548                      if (!ast_test_flag(peerflags, OPT_ORIGINAL_CLID))
00549                         ast_set_callerid(o->chan, ast_strlen_zero(in->macroexten) ? in->exten : in->macroexten, get_cid_name(cidname, sizeof(cidname), in), NULL);
00550                   }
00551                }
00552                /* Hangup the original channel now, in case we needed it */
00553                ast_hangup(winner);
00554                continue;
00555             }
00556             f = ast_read(winner);
00557             if (f) {
00558                if (f->frametype == AST_FRAME_CONTROL) {
00559                   switch(f->subclass) {
00560                   case AST_CONTROL_ANSWER:
00561                      /* This is our guy if someone answered. */
00562                      if (!peer) {
00563                         if (option_verbose > 2)
00564                            ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
00565                         peer = o->chan;
00566                         ast_copy_flags(peerflags, o,
00567                                   OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
00568                                   OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
00569                                   OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
00570                                   DIAL_NOFORWARDHTML);
00571                      }
00572                      /* If call has been answered, then the eventual hangup is likely to be normal hangup */
00573                      in->hangupcause = AST_CAUSE_NORMAL_CLEARING;
00574                      o->chan->hangupcause = AST_CAUSE_NORMAL_CLEARING;
00575                      break;
00576                   case AST_CONTROL_BUSY:
00577                      if (option_verbose > 2)
00578                         ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
00579                      in->hangupcause = o->chan->hangupcause;
00580                      ast_hangup(o->chan);
00581                      o->chan = NULL;
00582                      ast_clear_flag(o, DIAL_STILLGOING); 
00583                      HANDLE_CAUSE(AST_CAUSE_BUSY, in);
00584                      break;
00585                   case AST_CONTROL_CONGESTION:
00586                      if (option_verbose > 2)
00587                         ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
00588                      in->hangupcause = o->chan->hangupcause;
00589                      ast_hangup(o->chan);
00590                      o->chan = NULL;
00591                      ast_clear_flag(o, DIAL_STILLGOING);
00592                      HANDLE_CAUSE(AST_CAUSE_CONGESTION, in);
00593                      break;
00594                   case AST_CONTROL_RINGING:
00595                      if (option_verbose > 2)
00596                         ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
00597                      if (!(*sentringing) && !ast_test_flag(outgoing, OPT_MUSICBACK)) {
00598                         ast_indicate(in, AST_CONTROL_RINGING);
00599                         (*sentringing)++;
00600                      }
00601                      break;
00602                   case AST_CONTROL_PROGRESS:
00603                      if (option_verbose > 2)
00604                         ast_verbose ( VERBOSE_PREFIX_3 "%s is making progress passing it to %s\n", o->chan->name,in->name);
00605                      if (!ast_test_flag(outgoing, OPT_RINGBACK))
00606                         ast_indicate(in, AST_CONTROL_PROGRESS);
00607                      break;
00608                   case AST_CONTROL_VIDUPDATE:
00609                      if (option_verbose > 2)
00610                         ast_verbose ( VERBOSE_PREFIX_3 "%s requested a video update, passing it to %s\n", o->chan->name,in->name);
00611                      ast_indicate(in, AST_CONTROL_VIDUPDATE);
00612                      break;
00613                   case AST_CONTROL_PROCEEDING:
00614                      if (option_verbose > 2)
00615                         ast_verbose ( VERBOSE_PREFIX_3 "%s is proceeding passing it to %s\n", o->chan->name,in->name);
00616                      if (!ast_test_flag(outgoing, OPT_RINGBACK))
00617                         ast_indicate(in, AST_CONTROL_PROCEEDING);
00618                      break;
00619                   case AST_CONTROL_HOLD:
00620                      if (option_verbose > 2)
00621                         ast_verbose(VERBOSE_PREFIX_3 "Call on %s placed on hold\n", o->chan->name);
00622                      ast_indicate(in, AST_CONTROL_HOLD);
00623                      break;
00624                   case AST_CONTROL_UNHOLD:
00625                      if (option_verbose > 2)
00626                         ast_verbose(VERBOSE_PREFIX_3 "Call on %s left from hold\n", o->chan->name);
00627                      ast_indicate(in, AST_CONTROL_UNHOLD);
00628                      break;
00629                   case AST_CONTROL_OFFHOOK:
00630                   case AST_CONTROL_FLASH:
00631                      /* Ignore going off hook and flash */
00632                      break;
00633                   case -1:
00634                      if (!ast_test_flag(outgoing, OPT_RINGBACK | OPT_MUSICBACK)) {
00635                         if (option_verbose > 2)
00636                            ast_verbose( VERBOSE_PREFIX_3 "%s stopped sounds\n", o->chan->name);
00637                         ast_indicate(in, -1);
00638                         (*sentringing) = 0;
00639                      }
00640                      break;
00641                   default:
00642                      ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
00643                   }
00644                } else if (single && (f->frametype == AST_FRAME_VOICE) && 
00645                         !(ast_test_flag(outgoing, OPT_RINGBACK|OPT_MUSICBACK))) {
00646                   if (ast_write(in, f)) 
00647                      ast_log(LOG_DEBUG, "Unable to forward frame\n");
00648                } else if (single && (f->frametype == AST_FRAME_IMAGE) && 
00649                         !(ast_test_flag(outgoing, OPT_RINGBACK|OPT_MUSICBACK))) {
00650                   if (ast_write(in, f))
00651                      ast_log(LOG_DEBUG, "Unable to forward image\n");
00652                } else if (single && (f->frametype == AST_FRAME_TEXT) && 
00653                         !(ast_test_flag(outgoing, OPT_RINGBACK|OPT_MUSICBACK))) {
00654                   if (ast_write(in, f))
00655                      ast_log(LOG_DEBUG, "Unable to text\n");
00656                } else if (single && (f->frametype == AST_FRAME_HTML) && !ast_test_flag(outgoing, DIAL_NOFORWARDHTML))
00657                   ast_channel_sendhtml(in, f->subclass, f->data, f->datalen);
00658 
00659                ast_frfree(f);
00660             } else {
00661                in->hangupcause = o->chan->hangupcause;
00662                ast_hangup(o->chan);
00663                o->chan = NULL;
00664                ast_clear_flag(o, DIAL_STILLGOING);
00665                HANDLE_CAUSE(in->hangupcause, in);
00666             }
00667          }
00668          o = o->next;
00669       }
00670       if (winner == in) {
00671          f = ast_read(in);
00672 #if 0
00673          if (f && (f->frametype != AST_FRAME_VOICE))
00674             printf("Frame type: %d, %d\n", f->frametype, f->subclass);
00675          else if (!f || (f->frametype != AST_FRAME_VOICE))
00676             printf("Hangup received on %s\n", in->name);
00677 #endif
00678          if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
00679             /* Got hung up */
00680             *to=-1;
00681             ast_cdr_noanswer(in->cdr);
00682             strcpy(status, "CANCEL");
00683             if (f)
00684                ast_frfree(f);
00685             return NULL;
00686          }
00687 
00688          if (f && (f->frametype == AST_FRAME_DTMF)) {
00689             if (ast_test_flag(peerflags, OPT_DTMF_EXIT)) {
00690                context = pbx_builtin_getvar_helper(in, "EXITCONTEXT");
00691                if (onedigit_goto(in, context, (char) f->subclass, 1)) {
00692                   if (option_verbose > 3)
00693                      ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
00694                   *to=0;
00695                   ast_cdr_noanswer(in->cdr);
00696                   *result = f->subclass;
00697                   strcpy(status, "CANCEL");
00698                   ast_frfree(f);
00699                   return NULL;
00700                }
00701             }
00702 
00703             if (ast_test_flag(peerflags, OPT_CALLER_HANGUP) && 
00704                     (f->subclass == '*')) { /* hmm it it not guarenteed to be '*' anymore. */
00705                if (option_verbose > 3)
00706                   ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
00707                *to=0;
00708                ast_cdr_noanswer(in->cdr);
00709                strcpy(status, "CANCEL");
00710                ast_frfree(f);
00711                return NULL;
00712             }
00713          }
00714 
00715          /* Forward HTML stuff */
00716          if (single && f && (f->frametype == AST_FRAME_HTML) && !ast_test_flag(outgoing, DIAL_NOFORWARDHTML)) 
00717             ast_channel_sendhtml(outgoing->chan, f->subclass, f->data, f->datalen);
00718          
00719 
00720          if (single && ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_DTMF)))  {
00721             if (ast_write(outgoing->chan, f))
00722                ast_log(LOG_WARNING, "Unable to forward voice\n");
00723          }
00724          if (single && (f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_VIDUPDATE)) {
00725             if (option_verbose > 2)
00726                ast_verbose ( VERBOSE_PREFIX_3 "%s requested a video update, passing it to %s\n", in->name,outgoing->chan->name);
00727             ast_indicate(outgoing->chan, AST_CONTROL_VIDUPDATE);
00728          }
00729          ast_frfree(f);
00730       }
00731       if (!*to && (option_verbose > 2))
00732          ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
00733       if (!*to || ast_check_hangup(in)) {
00734          ast_cdr_noanswer(in->cdr);
00735       }
00736       
00737    }
00738 
00739    return peer;
00740    
00741 }
00742 
00743 static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags *peerflags, int *continue_exec)
00744 {
00745    int res=-1;
00746    struct localuser *u;
00747    char *tech, *number, *rest, *cur;
00748    char privcid[256];
00749    char privintro[1024];
00750    struct localuser *outgoing=NULL, *tmp;
00751    struct ast_channel *peer;
00752    int to;
00753    int numbusy = 0;
00754    int numcongestion = 0;
00755    int numnochan = 0;
00756    int cause;
00757    char numsubst[AST_MAX_EXTENSION];
00758    char restofit[AST_MAX_EXTENSION];
00759    char cidname[AST_MAX_EXTENSION];
00760    char toast[80];
00761    char *newnum;
00762    char *l;
00763    int privdb_val=0;
00764    unsigned int calldurationlimit=0;
00765    struct ast_bridge_config config;
00766    long timelimit = 0;
00767    long play_warning = 0;
00768    long warning_freq=0;
00769    char *warning_sound=NULL;
00770    char *end_sound=NULL;
00771    char *start_sound=NULL;
00772    char *dtmfcalled=NULL, *dtmfcalling=NULL;
00773    char *var;
00774    char status[256] = "INVALIDARGS";
00775    int play_to_caller=0,play_to_callee=0;
00776    int sentringing=0, moh=0;
00777    char *outbound_group = NULL;
00778    char *macro_result = NULL, *macro_transfer_dest = NULL;
00779    int digit = 0, result = 0;
00780    time_t start_time, answer_time, end_time;
00781    struct ast_app *app = NULL;
00782 
00783    char *parse;
00784    AST_DECLARE_APP_ARGS(args,
00785               AST_APP_ARG(peers);
00786               AST_APP_ARG(timeout);
00787               AST_APP_ARG(options);
00788               AST_APP_ARG(url);
00789    );
00790    struct ast_flags opts = { 0, };
00791    char *opt_args[OPT_ARG_ARRAY_SIZE];
00792 
00793    if (ast_strlen_zero(data)) {
00794       ast_log(LOG_WARNING, "Dial requires an argument (technology/number)\n");
00795       pbx_builtin_setvar_helper(chan, "DIALSTATUS", status);
00796       return -1;
00797    }
00798 
00799    LOCAL_USER_ADD(u);
00800 
00801    parse = ast_strdupa(data);
00802    
00803    AST_STANDARD_APP_ARGS(args, parse);
00804 
00805    if (!ast_strlen_zero(args.options)) {
00806       if (ast_app_parse_options(dial_exec_options, &opts, opt_args, args.options)) {
00807          pbx_builtin_setvar_helper(chan, "DIALSTATUS", status);
00808          LOCAL_USER_REMOVE(u);
00809          return -1;
00810       }
00811    }
00812 
00813    if (ast_strlen_zero(args.peers)) {
00814       ast_log(LOG_WARNING, "Dial requires an argument (technology/number)\n");
00815       pbx_builtin_setvar_helper(chan, "DIALSTATUS", status);
00816       LOCAL_USER_REMOVE(u);
00817       return -1;
00818    }
00819 
00820    if (ast_test_flag(&opts, OPT_DURATION_STOP) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_STOP])) {
00821       calldurationlimit = atoi(opt_args[OPT_ARG_DURATION_STOP]);
00822       if (option_verbose > 2)
00823          ast_verbose(VERBOSE_PREFIX_3 "Setting call duration limit to %d seconds.\n",calldurationlimit);       
00824    }
00825 
00826    if (ast_test_flag(&opts, OPT_SENDDTMF) && !ast_strlen_zero(opt_args[OPT_ARG_SEND