70f28ac7f10f8deafd26b7daedaba94ecfd7aed5
[asterisk/asterisk.git] / apps / app_dial.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Trivial application to dial a channel and send an URL on answer
5  * 
6  * Copyright (C) 1999-2004, Digium, Inc.
7  *
8  * Mark Spencer <markster@digium.com>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <asterisk/lock.h>
15 #include <asterisk/file.h>
16 #include <asterisk/logger.h>
17 #include <asterisk/channel.h>
18 #include <asterisk/pbx.h>
19 #include <asterisk/options.h>
20 #include <asterisk/module.h>
21 #include <asterisk/translate.h>
22 #include <asterisk/say.h>
23 #include <asterisk/config.h>
24 #include <asterisk/features.h>
25 #include <asterisk/musiconhold.h>
26 #include <asterisk/callerid.h>
27 #include <asterisk/utils.h>
28 #include <asterisk/app.h>
29 #include <asterisk/causes.h>
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <unistd.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <sys/time.h>
37 #include <sys/signal.h>
38 #include <netinet/in.h>
39
40 static char *tdesc = "Dialing Application";
41
42 static char *app = "Dial";
43
44 static char *synopsis = "Place a call and connect to the current channel";
45
46 static char *descrip =
47 "  Dial(Technology/resource[&Technology2/resource2...][|timeout][|options][|URL]):\n"
48 "Requests one or more channels and places specified outgoing calls on them.\n"
49 "As soon as a channel answers, the Dial app will answer the originating\n"
50 "channel (if it needs to be answered) and will bridge a call with the channel\n"
51 "which first answered. All other calls placed by the Dial app will be hung up.\n"
52 "If a timeout is not specified, the Dial application will wait indefinitely\n"
53 "until either one of the called channels answers, the user hangs up, or all\n"
54 "channels return busy or error. In general, the dialer will return 0 if it\n"
55 "was unable to place the call, or the timeout expired. However, if all\n"
56 "channels were busy, and there exists an extension with priority n+101 (where\n"
57 "n is the priority of the dialer instance), then it will be the next\n"
58 "executed extension (this allows you to setup different behavior on busy from\n"
59 "no-answer).\n"
60 "  This application returns -1 if the originating channel hangs up, or if the\n"
61 "call is bridged and either of the parties in the bridge terminate the call.\n"
62 "The option string may contain zero or more of the following characters:\n"
63 "      't' -- allow the called user transfer the calling user by hitting #.\n"
64 "      'T' -- allow the calling user to transfer the call by hitting #.\n"
65 "      'f' -- Forces callerid to be set as the extension of the line \n"
66 "             making/redirecting the outgoing call. For example, some PSTNs\n"
67 "             don't allow callerids from other extensions then the ones\n"
68 "             that are assigned to you.\n"
69 "      'r' -- indicate ringing to the calling party, pass no audio until answered.\n"
70 "      'm' -- provide hold music to the calling party until answered.\n"
71 "      'M(x[^arg]) -- Executes the macro (x with ^ delim arg list) upon connect of the call.\n"
72 "                     Also, the macro can set the MACRO_RESULT variable to do the following:\n"
73 "                     -- ABORT - Hangup both legs of the call.\n"
74 "                     -- CONGESTION - Behave as if line congestion was encountered.\n"
75 "                     -- BUSY - Behave as if a busy signal was encountered. (n+101)\n"
76 "                     -- CONTINUE - Hangup the called party and continue on in the dialplan.\n"
77 "                     -- GOTO:<context>^<exten>^<priority> - Transfer the call.\n"
78 "      'h' -- allow callee to hang up by hitting *.\n"
79 "      'H' -- allow caller to hang up by hitting *.\n"
80 "      'C' -- reset call detail record for this call.\n"
81 "      'P[(x)]' -- privacy mode, using 'x' as database if provided.\n"
82 "      'g' -- goes on in context if the destination channel hangs up\n"
83 "      'A(x)' -- play an announcement to the called party, using x as file\n"
84 "      'S(x)' -- hangup the call after x seconds AFTER called party picked up\n"        
85 "      'D([digits])'  -- Send DTMF digit string *after* called party has answered\n"
86 "             but before the bridge. (w=500ms sec pause)\n"
87 "      'L(x[:y][:z])' -- Limit the call to 'x' ms warning when 'y' ms are left\n"
88 "             repeated every 'z' ms) Only 'x' is required, 'y' and 'z' are optional.\n"
89 "             The following special variables are optional:\n"
90 "             * LIMIT_PLAYAUDIO_CALLER    yes|no (default yes)\n"
91 "                                         Play sounds to the caller.\n"
92 "             * LIMIT_PLAYAUDIO_CALLEE    yes|no\n"
93 "                                         Play sounds to the callee.\n"
94 "             * LIMIT_TIMEOUT_FILE        File to play when time is up.\n"
95 "             * LIMIT_CONNECT_FILE        File to play when call begins.\n"
96 "             * LIMIT_WARNING_FILE        File to play as warning if 'y' is defined.\n"
97 "                        'timeleft' is a special sound macro to auto-say the time \n"
98 "                        left and is the default.\n\n"
99 "  In addition to transferring the call, a call may be parked and then picked\n"
100 "up by another user.\n"
101 "  The optional URL will be sent to the called party if the channel supports it.\n"
102 "  If the OUTBOUND_GROUP variable is set, all peer channels created by this\n"
103 "  application will be put into that group (as in SetGroup).\n"
104 "  This application sets the following channel variables upon completion:\n"
105 "      DIALEDTIME    Time from dial to answer\n" 
106 "      ANSWEREDTIME  Time for actual call\n"
107 "      DIALSTATUS    The status of the call as a text string, one of\n"
108 "             CHANUNAVAIL | CONGESTION | NOANSWER | BUSY | ANSWER | CANCEL\n"
109 "";
110
111 /* We define a customer "local user" structure because we
112    use it not only for keeping track of what is in use but
113    also for keeping track of who we're dialing. */
114
115 struct localuser {
116         struct ast_channel *chan;
117         int stillgoing;
118         int allowredirect_in;
119         int allowredirect_out;
120         int ringbackonly;
121         int musiconhold;
122         int allowdisconnect_in;
123         int allowdisconnect_out;
124         int forcecallerid;
125         struct localuser *next;
126 };
127
128 LOCAL_USER_DECL;
129
130 static void hanguptree(struct localuser *outgoing, struct ast_channel *exception)
131 {
132         /* Hang up a tree of stuff */
133         struct localuser *oo;
134         while(outgoing) {
135                 /* Hangup any existing lines we have open */
136                 if (outgoing->chan && (outgoing->chan != exception))
137                         ast_hangup(outgoing->chan);
138                 oo = outgoing;
139                 outgoing=outgoing->next;
140                 free(oo);
141         }
142 }
143
144 #define AST_MAX_WATCHERS 256
145
146 #define HANDLE_CAUSE(blah, bleh) do { \
147         switch(cause) { \
148         case AST_CAUSE_BUSY: \
149                 if (bleh->cdr) \
150                         ast_cdr_busy(bleh->cdr); \
151                 numbusy++; \
152                 break; \
153         case AST_CAUSE_CONGESTION: \
154         case AST_CAUSE_UNREGISTERED: \
155                 if (bleh->cdr) \
156                         ast_cdr_busy(bleh->cdr); \
157                 numcongestion++; \
158                 break; \
159         default: \
160                 numnochan++; \
161                 break; \
162         } \
163 } while(0)
164
165
166 static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localuser *outgoing, int *to, int *allowredir_in, int *allowredir_out, int *allowdisconnect_in, int *allowdisconnect_out, int *sentringing, char *status, size_t statussize, int busystart, int nochanstart, int congestionstart)
167 {
168         struct localuser *o;
169         int found;
170         int numlines;
171         int numbusy = busystart;
172         int numcongestion = congestionstart;
173         int numnochan = nochanstart;
174         int prestart = busystart + congestionstart + nochanstart;
175         int cause;
176         int orig = *to;
177         struct ast_frame *f;
178         struct ast_channel *peer = NULL;
179         struct ast_channel *watchers[AST_MAX_WATCHERS];
180         int pos;
181         int single;
182         struct ast_channel *winner;
183         
184         single = (outgoing && !outgoing->next && !outgoing->musiconhold && !outgoing->ringbackonly);
185         
186         if (single) {
187                 /* Turn off hold music, etc */
188                 ast_deactivate_generator(in);
189                 /* If we are calling a single channel, make them compatible for in-band tone purpose */
190                 ast_channel_make_compatible(outgoing->chan, in);
191         }
192         
193         
194         while(*to && !peer) {
195                 o = outgoing;
196                 found = -1;
197                 pos = 1;
198                 numlines = prestart;
199                 watchers[0] = in;
200                 while(o) {
201                         /* Keep track of important channels */
202                         if (o->stillgoing && o->chan) {
203                                 watchers[pos++] = o->chan;
204                                 found = 1;
205                         }
206                         o = o->next;
207                         numlines++;
208                 }
209                 if (found < 0) {
210                         if (numlines == (numbusy + numcongestion + numnochan)) {
211                                 if (option_verbose > 2)
212                                         ast_verbose( VERBOSE_PREFIX_2 "Everyone is busy/congested at this time\n");
213                                 if (numbusy)
214                                         strncpy(status, "BUSY", statussize - 1);
215                                 else if (numcongestion)
216                                         strncpy(status, "CONGESTION", statussize - 1);
217                                 else if (numnochan)
218                                         strncpy(status, "CHANUNAVAIL", statussize - 1);
219                                 /* See if there is a special busy message */
220                                 if (ast_exists_extension(in, in->context, in->exten, in->priority + 101, in->cid.cid_num)) 
221                                         in->priority+=100;
222                         } else {
223                                 if (option_verbose > 2)
224                                         ast_verbose( VERBOSE_PREFIX_2 "No one is available to answer at this time (%d, %d/%d/%d)\n", numlines, numbusy, numcongestion, numnochan);
225                         }
226                         *to = 0;
227                         return NULL;
228                 }
229                 winner = ast_waitfor_n(watchers, pos, to);
230                 o = outgoing;
231                 while(o) {
232                         if (o->stillgoing && o->chan && (o->chan->_state == AST_STATE_UP)) {
233                                 if (!peer) {
234                                         if (option_verbose > 2)
235                                                 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
236                                         peer = o->chan;
237                                         *allowredir_in = o->allowredirect_in;
238                                         *allowredir_out = o->allowredirect_out;
239                                         *allowdisconnect_in = o->allowdisconnect_in;
240                                         *allowdisconnect_out = o->allowdisconnect_out;
241                                 }
242                         } else if (o->chan && (o->chan == winner)) {
243                                 if (!ast_strlen_zero(o->chan->call_forward)) {
244                                         char tmpchan[256]="";
245                                         char *stuff;
246                                         char *tech;
247                                         strncpy(tmpchan, o->chan->call_forward, sizeof(tmpchan) - 1);
248                                         if ((stuff = strchr(tmpchan, '/'))) {
249                                                 *stuff = '\0';
250                                                 stuff++;
251                                                 tech = tmpchan;
252                                         } else {
253                                                 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
254                                                 stuff = tmpchan;
255                                                 tech = "Local";
256                                         }
257                                         /* Before processing channel, go ahead and check for forwarding */
258                                         if (option_verbose > 2)
259                                                 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
260                                         /* Setup parameters */
261                                         o->chan = ast_request(tech, in->nativeformats, stuff, &cause);
262                                         if (!o->chan) {
263                                                 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
264                                                 o->stillgoing = 0;
265                                                 HANDLE_CAUSE(cause, in);
266                                         } else {
267                                                 if (o->chan->cid.cid_num)
268                                                         free(o->chan->cid.cid_num);
269                                                 o->chan->cid.cid_num = NULL;
270                                                 if (o->chan->cid.cid_name)
271                                                         free(o->chan->cid.cid_name);
272                                                 o->chan->cid.cid_name = NULL;
273
274                                                 if (o->forcecallerid) {
275                                                         char *newcid = NULL;
276
277                                                         if (strlen(in->macroexten))
278                                                                 newcid = in->macroexten;
279                                                         else
280                                                                 newcid = in->exten;
281                                                         o->chan->cid.cid_num = strdup(newcid);
282                                                         strncpy(o->chan->accountcode, winner->accountcode, sizeof(o->chan->accountcode) - 1);
283                                                         o->chan->cdrflags = winner->cdrflags;
284                                                         if (!o->chan->cid.cid_num)
285                                                                 ast_log(LOG_WARNING, "Out of memory\n");
286                                                 } else {
287                                                         if (in->cid.cid_num) {
288                                                                 o->chan->cid.cid_num = strdup(in->cid.cid_num);
289                                                                 if (!o->chan->cid.cid_num)
290                                                                         ast_log(LOG_WARNING, "Out of memory\n");        
291                                                         }
292                                                         if (in->cid.cid_name) {
293                                                                 o->chan->cid.cid_name = strdup(in->cid.cid_name);
294                                                                 if (!o->chan->cid.cid_name)
295                                                                         ast_log(LOG_WARNING, "Out of memory\n");        
296                                                         }
297                                                         strncpy(o->chan->accountcode, in->accountcode, sizeof(o->chan->accountcode) - 1);
298                                                         o->chan->cdrflags = in->cdrflags;
299                                                 }
300
301                                                 if (in->cid.cid_ani) {
302                                                         if (o->chan->cid.cid_ani)
303                                                                 free(o->chan->cid.cid_ani);
304                                                         o->chan->cid.cid_ani = malloc(strlen(in->cid.cid_ani) + 1);
305                                                         if (o->chan->cid.cid_ani)
306                                                                 strncpy(o->chan->cid.cid_ani, in->cid.cid_ani, strlen(in->cid.cid_ani) + 1);
307                                                         else
308                                                                 ast_log(LOG_WARNING, "Out of memory\n");
309                                                 }
310                                                 if (o->chan->cid.cid_rdnis) 
311                                                         free(o->chan->cid.cid_rdnis);
312                                                 if (!ast_strlen_zero(in->macroexten))
313                                                         o->chan->cid.cid_rdnis = strdup(in->macroexten);
314                                                 else
315                                                         o->chan->cid.cid_rdnis = strdup(in->exten);
316                                                 if (ast_call(o->chan, tmpchan, 0)) {
317                                                         ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
318                                                         o->stillgoing = 0;
319                                                         ast_hangup(o->chan);
320                                                         o->chan = NULL;
321                                                         numnochan++;
322                                                 }
323                                         }
324                                         /* Hangup the original channel now, in case we needed it */
325                                         ast_hangup(winner);
326                                         continue;
327                                 }
328                                 f = ast_read(winner);
329                                 if (f) {
330                                         if (f->frametype == AST_FRAME_CONTROL) {
331                                                 switch(f->subclass) {
332                                             case AST_CONTROL_ANSWER:
333                                                         /* This is our guy if someone answered. */
334                                                         if (!peer) {
335                                                                 if (option_verbose > 2)
336                                                                         ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
337                                                                 peer = o->chan;
338                                                                 *allowredir_in = o->allowredirect_in;
339                                                                 *allowredir_out = o->allowredirect_out;
340                                                                 *allowdisconnect_in = o->allowdisconnect_in;
341                                                                 *allowdisconnect_out = o->allowdisconnect_out;
342                                                         }
343                                                         break;
344                                                 case AST_CONTROL_BUSY:
345                                                         if (option_verbose > 2)
346                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
347                                                         in->hangupcause = o->chan->hangupcause;
348                                                         ast_hangup(o->chan);
349                                                         o->chan = NULL;
350                                                         o->stillgoing = 0;
351                                                         HANDLE_CAUSE(AST_CAUSE_BUSY, in);
352                                                         break;
353                                                 case AST_CONTROL_CONGESTION:
354                                                         if (option_verbose > 2)
355                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
356                                                         in->hangupcause = o->chan->hangupcause;
357                                                         ast_hangup(o->chan);
358                                                         o->chan = NULL;
359                                                         o->stillgoing = 0;
360                                                         HANDLE_CAUSE(AST_CAUSE_CONGESTION, in);
361                                                         break;
362                                                 case AST_CONTROL_RINGING:
363                                                         if (option_verbose > 2)
364                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
365                                                         if (!(*sentringing) && !outgoing->musiconhold) {
366                                                                 ast_indicate(in, AST_CONTROL_RINGING);
367                                                                 (*sentringing)++;
368                                                         }
369                                                         break;
370                                                 case AST_CONTROL_PROGRESS:
371                                                         if (option_verbose > 2)
372                                                                 ast_verbose ( VERBOSE_PREFIX_3 "%s is making progress passing it to %s\n", o->chan->name,in->name);
373                                                         if (!outgoing->ringbackonly)
374                                                                 ast_indicate(in, AST_CONTROL_PROGRESS);
375                                                         break;
376                                                 case AST_CONTROL_OFFHOOK:
377                                                 case AST_CONTROL_FLASH:
378                                                         /* Ignore going off hook and flash */
379                                                         break;
380                                                 case -1:
381                                                         if (!outgoing->ringbackonly && !outgoing->musiconhold) {
382                                                                 if (option_verbose > 2)
383                                                                         ast_verbose( VERBOSE_PREFIX_3 "%s stopped sounds\n", o->chan->name);
384                                                                 ast_indicate(in, -1);
385                                                                 (*sentringing) = 0;
386                                                         }
387                                                         break;
388                                                 default:
389                                                         ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
390                                                 }
391                                         } else if (single && (f->frametype == AST_FRAME_VOICE) && 
392                                                                 !(outgoing->ringbackonly || outgoing->musiconhold)) {
393                                                 if (ast_write(in, f)) 
394                                                         ast_log(LOG_WARNING, "Unable to forward frame\n");
395                                         } else if (single && (f->frametype == AST_FRAME_IMAGE) && 
396                                                                 !(outgoing->ringbackonly || outgoing->musiconhold)) {
397                                                 if (ast_write(in, f))
398                                                         ast_log(LOG_WARNING, "Unable to forward image\n");
399                                         }
400                                         ast_frfree(f);
401                                 } else {
402                                         in->hangupcause = o->chan->hangupcause;
403                                         ast_hangup(o->chan);
404                                         o->chan = NULL;
405                                         o->stillgoing = 0;
406                                 }
407                         }
408                         o = o->next;
409                 }
410                 if (winner == in) {
411                         f = ast_read(in);
412 #if 0
413                         if (f && (f->frametype != AST_FRAME_VOICE))
414                                         printf("Frame type: %d, %d\n", f->frametype, f->subclass);
415                         else if (!f || (f->frametype != AST_FRAME_VOICE))
416                                 printf("Hangup received on %s\n", in->name);
417 #endif
418                         if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
419                                 /* Got hung up */
420                                 *to=-1;
421                                 strncpy(status, "CANCEL", statussize - 1);
422                                 return NULL;
423                         }
424                         if (f && (f->frametype == AST_FRAME_DTMF) && *allowdisconnect_out &&
425                                 (f->subclass == '*')) {
426                             if (option_verbose > 3)
427                                 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
428                                 *to=0;
429                                 strcpy(status, "CANCEL");
430                                 return NULL;
431                         }
432                         if (single && ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_DTMF)))  {
433                                 if (ast_write(outgoing->chan, f))
434                                         ast_log(LOG_WARNING, "Unable to forward voice\n");
435                                 ast_frfree(f);
436                         }
437                 }
438                 if (!*to && (option_verbose > 2))
439                         ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
440         }
441
442         return peer;
443         
444 }
445
446 static int dial_exec(struct ast_channel *chan, void *data)
447 {
448         int res=-1;
449         struct localuser *u;
450         char *info, *peers, *timeout, *tech, *number, *rest, *cur;
451         char  privdb[256] = "", *s;
452         char  announcemsg[256] = "", *ann;
453         struct localuser *outgoing=NULL, *tmp;
454         struct ast_channel *peer;
455         int to;
456         int allowredir_in=0;
457         int allowredir_out=0;
458         int allowdisconnect_in=0;
459         int allowdisconnect_out=0;
460         int hasmacro = 0;
461         int privacy=0;
462         int announce=0;
463         int resetcdr=0;
464         int numbusy = 0;
465         int numcongestion = 0;
466         int numnochan = 0;
467         int cause;
468         char numsubst[AST_MAX_EXTENSION];
469         char restofit[AST_MAX_EXTENSION];
470         char *transfer = NULL;
471         char *newnum;
472         char *l;
473         char *url=NULL; /* JDG */
474         struct ast_var_t *current;
475         struct varshead *headp, *newheadp;
476         struct ast_var_t *newvar;
477         int go_on=0;
478         unsigned int calldurationlimit=0;
479         char *cdl;
480         time_t now;
481         struct ast_bridge_config config;
482         long timelimit = 0;
483         long play_warning = 0;
484         long warning_freq=0;
485         char *warning_sound=NULL;
486         char *end_sound=NULL;
487         char *start_sound=NULL;
488         char *limitptr;
489         char limitdata[256];
490         char *sdtmfptr;
491         char sdtmfdata[256] = "";
492         char *stack,*var;
493         char *mac = NULL, *macroname = NULL;
494         char status[256]="";
495         char toast[80];
496         int play_to_caller=0,play_to_callee=0;
497         int playargs=0, sentringing=0, moh=0;
498         char *varname;
499         int vartype;
500         char *outbound_group = NULL;
501         char *macro_result = NULL, *macro_transfer_dest = NULL;
502         int digit = 0;
503         time_t start_time, answer_time, end_time;
504         struct ast_app *app = NULL;
505
506         if (!data) {
507                 ast_log(LOG_WARNING, "Dial requires an argument (technology1/number1&technology2/number2...|optional timeout|options)\n");
508                 return -1;
509         }
510
511         if (!(info = ast_strdupa(data))) {
512                 ast_log(LOG_WARNING, "Unable to dupe data :(\n");
513                 return -1;
514         }
515         LOCAL_USER_ADD(u);
516         
517         peers = info;
518         if (peers) {
519                 
520                 timeout = strchr(info, '|');
521                 if (timeout) {
522                         *timeout = '\0';
523                         timeout++;
524                         transfer = strchr(timeout, '|');
525                         if (transfer) {
526                                 *transfer = '\0';
527                                 transfer++;
528                                 /* JDG */
529                                 url = strchr(transfer, '|');
530                                 if (url) {
531                                         *url = '\0';
532                                         url++;
533                                         if (option_debug)
534                                                 ast_log(LOG_DEBUG, "DIAL WITH URL=%s_\n", url);
535                                 } else 
536                                         if (option_debug) {
537                                                 ast_log(LOG_DEBUG, "SIMPLE DIAL (NO URL)\n");
538                                         }
539                                 /* /JDG */
540                         }
541                 }
542         } else
543                 timeout = NULL;
544         if (!peers || ast_strlen_zero(peers)) {
545                 ast_log(LOG_WARNING, "Dial argument takes format (technology1/number1&technology2/number2...|optional timeout)\n");
546                 goto out;
547         }
548         
549
550         if (transfer) {
551
552                 /* Extract call duration limit */
553                 if ((cdl = strstr(transfer, "S("))) {
554                         calldurationlimit=atoi(cdl+2);
555                         if (option_verbose > 2)
556                                 ast_verbose(VERBOSE_PREFIX_3 "Setting call duration limit to %i seconds.\n",calldurationlimit);                 
557                 } 
558
559                 /* DTMF SCRIPT*/
560                 if ((sdtmfptr = strstr(transfer, "D("))) {
561                         strncpy(sdtmfdata, sdtmfptr + 2, sizeof(sdtmfdata) - 1);
562                         /* Overwrite with X's what was the sdtmf info */
563                         while (*sdtmfptr && (*sdtmfptr != ')')) 
564                                 *(sdtmfptr++) = 'X';
565                         if (*sdtmfptr)
566                                 *sdtmfptr = 'X';
567                         /* Now find the end  */
568                         sdtmfptr = strchr(sdtmfdata, ')');
569                         if (sdtmfptr)
570                                 *sdtmfptr = '\0';
571                         else 
572                                 ast_log(LOG_WARNING, "D( Data lacking trailing ')'\n");
573                 }
574                 
575                 /* XXX LIMIT SUPPORT */
576                 if ((limitptr = strstr(transfer, "L("))) {
577                         strncpy(limitdata, limitptr + 2, sizeof(limitdata) - 1);
578                         /* Overwrite with X's what was the limit info */
579                         while(*limitptr && (*limitptr != ')')) 
580                                 *(limitptr++) = 'X';
581                         if (*limitptr)
582                                 *limitptr = 'X';
583                         /* Now find the end */
584                         limitptr = strchr(limitdata, ')');
585                         if (limitptr)
586                                 *limitptr = '\0';
587                         else
588                                 ast_log(LOG_WARNING, "Limit Data lacking trailing ')'\n");
589
590                         var = pbx_builtin_getvar_helper(chan,"LIMIT_PLAYAUDIO_CALLER");
591                         play_to_caller = var ? ast_true(var) : 1;
592                   
593                         var = pbx_builtin_getvar_helper(chan,"LIMIT_PLAYAUDIO_CALLEE");
594                         play_to_callee = var ? ast_true(var) : 0;
595                   
596                         if (!play_to_caller && !play_to_callee)
597                                 play_to_caller=1;
598                   
599                         var = pbx_builtin_getvar_helper(chan,"LIMIT_WARNING_FILE");
600                         warning_sound = var ? var : "timeleft";
601
602                         var = pbx_builtin_getvar_helper(chan,"LIMIT_TIMEOUT_FILE");
603                         end_sound = var ? var : NULL;
604
605                         var = pbx_builtin_getvar_helper(chan,"LIMIT_CONNECT_FILE");
606                         start_sound = var ? var : NULL;
607
608                         var=stack=limitdata;
609
610                         var = strsep(&stack, ":");
611                         if (var) {
612                                 timelimit = atol(var);
613                                 playargs++;
614                                 var = strsep(&stack, ":");
615                                 if (var) {
616                                         play_warning = atol(var);
617                                         playargs++;
618                                         var = strsep(&stack, ":");
619                                         if(var) {
620                                                 warning_freq = atol(var);
621                                                 playargs++;
622                                         }
623                                 }
624                         }
625                   
626                         if (!timelimit) {
627                                 timelimit=play_to_caller=play_to_callee=play_warning=warning_freq=0;
628                                 warning_sound=NULL;
629                         }
630                         /* undo effect of S(x) in case they are both used */
631                         calldurationlimit=0; 
632                         /* more efficient do it like S(x) does since no advanced opts*/
633                         if (!play_warning && !start_sound && !end_sound && timelimit) { 
634                                 calldurationlimit=timelimit/1000;
635                                 timelimit=play_to_caller=play_to_callee=play_warning=warning_freq=0;
636                         } else if (option_verbose > 2) {
637                                 ast_verbose(VERBOSE_PREFIX_3"Limit Data:\n");
638                                 ast_verbose(VERBOSE_PREFIX_3"timelimit=%ld\n",timelimit);
639                                 ast_verbose(VERBOSE_PREFIX_3"play_warning=%ld\n",play_warning);
640                                 ast_verbose(VERBOSE_PREFIX_3"play_to_caller=%s\n",play_to_caller ? "yes" : "no");
641                                 ast_verbose(VERBOSE_PREFIX_3"play_to_callee=%s\n",play_to_callee ? "yes" : "no");
642                                 ast_verbose(VERBOSE_PREFIX_3"warning_freq=%ld\n",warning_freq);
643                                 ast_verbose(VERBOSE_PREFIX_3"start_sound=%s\n",start_sound ? start_sound : "UNDEF");
644                                 ast_verbose(VERBOSE_PREFIX_3"warning_sound=%s\n",warning_sound ? warning_sound : "UNDEF");
645                                 ast_verbose(VERBOSE_PREFIX_3"end_sound=%s\n",end_sound ? end_sound : "UNDEF");
646                         }
647                 }
648                 
649                 /* XXX ANNOUNCE SUPPORT */
650                 if ((ann = strstr(transfer, "A("))) {
651                         announce = 1;
652                         strncpy(announcemsg, ann + 2, sizeof(announcemsg) - 1);
653                         /* Overwrite with X's what was the announce info */
654                         while(*ann && (*ann != ')')) 
655                                 *(ann++) = 'X';
656                         if (*ann)
657                                 *ann = 'X';
658                         /* Now find the end of the privdb */
659                         ann = strchr(announcemsg, ')');
660                         if (ann)
661                                 *ann = '\0';
662                         else {
663                                 ast_log(LOG_WARNING, "Transfer with Announce spec lacking trailing ')'\n");
664                                 announce = 0;
665                         }
666                 }
667                 
668                 /* Get the macroname from the dial option string */
669                 if ((mac = strstr(transfer, "M("))) {
670                         hasmacro = 1;
671                         macroname = ast_strdupa(mac + 2);
672                         while (*mac && (*mac != ')'))
673                                 *(mac++) = 'X';
674                         if (*mac)
675                                 *mac = 'X';
676                         else {
677                                 ast_log(LOG_WARNING, "Could not find macro to which we should jump.\n");
678                                 hasmacro = 0;
679                         }
680                         mac = strchr(macroname, ')');
681                         if (mac)
682                                 *mac = '\0';
683                         else {
684                                 ast_log(LOG_WARNING, "Macro flag set without trailing ')'\n");
685                                 hasmacro = 0;
686                         }
687                 }
688                 /* Extract privacy info from transfer */
689                 if ((s = strstr(transfer, "P("))) {
690                         privacy = 1;
691                         strncpy(privdb, s + 2, sizeof(privdb) - 1);
692                         /* Overwrite with X's what was the privacy info */
693                         while(*s && (*s != ')')) 
694                                 *(s++) = 'X';
695                         if (*s)
696                                 *s = 'X';
697                         /* Now find the end of the privdb */
698                         s = strchr(privdb, ')');
699                         if (s)
700                                 *s = '\0';
701                         else {
702                                 ast_log(LOG_WARNING, "Transfer with privacy lacking trailing ')'\n");
703                                 privacy = 0;
704                         }
705                 } else if (strchr(transfer, 'P')) {
706                         /* No specified privdb */
707                         privacy = 1;
708                 } else if (strchr(transfer, 'C')) {
709                         resetcdr = 1;
710                 }
711         }
712         if (resetcdr && chan->cdr)
713                 ast_cdr_reset(chan->cdr, 0);
714         if (ast_strlen_zero(privdb) && privacy) {
715                 /* If privdb is not specified and we are using privacy, copy from extension */
716                 strncpy(privdb, chan->exten, sizeof(privdb) - 1);
717         }
718         if (privacy) {
719                 l = chan->cid.cid_num;
720                 if (!l)
721                         l = "";
722                 ast_log(LOG_NOTICE, "Privacy DB is '%s', privacy is %d, clid is '%s'\n", privdb, privacy, l);
723         }
724
725         /* If a channel group has been specified, get it for use when we create peer channels */
726         outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP");
727
728         cur = peers;
729         do {
730                 /* Remember where to start next time */
731                 rest = strchr(cur, '&');
732                 if (rest) {
733                         *rest = 0;
734                         rest++;
735                 }
736                 /* Get a technology/[device:]number pair */
737                 tech = cur;
738                 number = strchr(tech, '/');
739                 if (!number) {
740                         ast_log(LOG_WARNING, "Dial argument takes format (technology1/[device:]number1&technology2/[device:]number2...|optional timeout)\n");
741                         goto out;
742                 }
743                 *number = '\0';
744                 number++;
745                 tmp = malloc(sizeof(struct localuser));
746                 if (!tmp) {
747                         ast_log(LOG_WARNING, "Out of memory\n");
748                         goto out;
749                 }
750                 memset(tmp, 0, sizeof(struct localuser));
751                 if (transfer) {
752                         if (strchr(transfer, 't'))
753                                 tmp->allowredirect_in = 1;
754                         else    tmp->allowredirect_in = 0;
755                         if (strchr(transfer, 'T'))
756                                 tmp->allowredirect_out = 1;
757                         else    tmp->allowredirect_out = 0;
758                         if (strchr(transfer, 'r'))
759                                 tmp->ringbackonly = 1;
760                         else    tmp->ringbackonly = 0;
761                         if (strchr(transfer, 'm'))
762                                 tmp->musiconhold = 1;
763                         else    tmp->musiconhold = 0;
764                         if (strchr(transfer, 'H'))
765                                 allowdisconnect_out = tmp->allowdisconnect_out = 1;
766                         else    allowdisconnect_out = tmp->allowdisconnect_out = 0;
767                         if(strchr(transfer, 'h'))
768                                 allowdisconnect_in = tmp->allowdisconnect_in = 1;
769                         else    allowdisconnect_in = tmp->allowdisconnect_in = 0;
770                         if(strchr(transfer, 'g'))
771                                 go_on=1;
772                         if (strchr(transfer, 'f'))
773                                 tmp->forcecallerid = 1;
774                         else    tmp->forcecallerid = 0;
775                 }
776                 strncpy(numsubst, number, sizeof(numsubst)-1);
777                 /* If we're dialing by extension, look at the extension to know what to dial */
778                 if ((newnum = strstr(numsubst, "BYEXTENSION"))) {
779                         strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit)-1);
780                         snprintf(newnum, sizeof(numsubst) - (newnum - numsubst), "%s%s", chan->exten,restofit);
781                         if (option_debug)
782                                 ast_log(LOG_DEBUG, "Dialing by extension %s\n", numsubst);
783                 }
784                 /* Request the peer */
785                 tmp->chan = ast_request(tech, chan->nativeformats, numsubst, &cause);
786                 if (!tmp->chan) {
787                         /* If we can't, just go on to the next call */
788                         ast_log(LOG_NOTICE, "Unable to create channel of type '%s' (cause %d)\n", tech, cause);
789                         HANDLE_CAUSE(cause, chan);
790                         cur = rest;
791                         continue;
792                 }
793                 if (!ast_strlen_zero(tmp->chan->call_forward)) {
794                         char tmpchan[256]="";
795                         char *stuff;
796                         char *tech;
797                         strncpy(tmpchan, tmp->chan->call_forward, sizeof(tmpchan) - 1);
798                         if ((stuff = strchr(tmpchan, '/'))) {
799                                 *stuff = '\0';
800                                 stuff++;
801                                 tech = tmpchan;
802                         } else {
803                                 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", tmp->chan->call_forward, tmp->chan->context);
804                                 stuff = tmpchan;
805                                 tech = "Local";
806                         }
807                         /* Before processing channel, go ahead and check for forwarding */
808                         if (option_verbose > 2)
809                                 ast_verbose(VERBOSE_PREFIX_3 "Forwarding %s to '%s/%s' (thanks to %s)\n", chan->name, tech, stuff, tmp->chan->name);
810                         /* Setup parameters */
811                         ast_hangup(tmp->chan);
812                         tmp->chan = ast_request(tech, chan->nativeformats, stuff, &cause);
813                         if (!tmp->chan) {
814                                 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause %d)\n", tech, stuff, cause);
815                                 HANDLE_CAUSE(cause, chan);
816                                 cur = rest;
817                                 continue;
818                         }
819                 }
820
821                 /* Contitionally copy channel variables to the newly created channel */
822                 headp = &chan->varshead;
823                 AST_LIST_TRAVERSE(headp, current, entries) {
824                         varname = ast_var_full_name(current);
825                         vartype = 0;
826                         if (varname) {
827                                 if (varname[0] == '_') {
828                                         vartype = 1;
829                                         if (varname[1] == '_')
830                                                 vartype = 2;
831                                 }
832                         }
833                         if (vartype == 1) {
834                                 newvar = ast_var_assign((char*)&(varname[1]), 
835                                                                                                 ast_var_value(current));
836                                 newheadp = &tmp->chan->varshead;
837                                 AST_LIST_INSERT_HEAD(newheadp, newvar, entries);
838                                 if (option_debug)
839                                         ast_log(LOG_DEBUG, "Copying soft-transferable variable %s.\n", 
840                                                                                                 ast_var_name(newvar));
841                         } else if (vartype == 2) {
842                                 newvar = ast_var_assign(ast_var_full_name(current), 
843                                                                                                 ast_var_value(current));
844                                 newheadp = &tmp->chan->varshead;
845                                 AST_LIST_INSERT_HEAD(newheadp, newvar, entries);
846                                 if (option_debug)
847                                         ast_log(LOG_DEBUG, "Copying hard-transferable variable %s.\n", 
848                                                                                                 ast_var_name(newvar));
849                         } else {
850                                 if (option_debug)
851                                         ast_log(LOG_DEBUG, "Not copying variable %s.\n", 
852                                                                                                 ast_var_name(current));
853                         }
854                 }
855
856                 tmp->chan->appl = "AppDial";
857                 tmp->chan->data = "(Outgoing Line)";
858                 tmp->chan->whentohangup = 0;
859                 if (tmp->chan->cid.cid_num)
860                         free(tmp->chan->cid.cid_num);
861                 tmp->chan->cid.cid_num = NULL;
862                 if (tmp->chan->cid.cid_name)
863                         free(tmp->chan->cid.cid_name);
864                 tmp->chan->cid.cid_name = NULL;
865                 if (tmp->chan->cid.cid_ani)
866                         free(tmp->chan->cid.cid_ani);
867                 tmp->chan->cid.cid_ani = NULL;
868
869                 if (chan->cid.cid_num) 
870                         tmp->chan->cid.cid_num = strdup(chan->cid.cid_num);
871                 if (chan->cid.cid_name) 
872                         tmp->chan->cid.cid_name = strdup(chan->cid.cid_name);
873                 if (chan->cid.cid_ani) 
874                         tmp->chan->cid.cid_ani = strdup(chan->cid.cid_ani);
875                 
876                 /* Copy language from incoming to outgoing */
877                 strncpy(tmp->chan->language, chan->language, sizeof(tmp->chan->language) - 1);
878                 strncpy(tmp->chan->accountcode, chan->accountcode, sizeof(tmp->chan->accountcode) - 1);
879                 tmp->chan->cdrflags = chan->cdrflags;
880                 if (ast_strlen_zero(tmp->chan->musicclass))
881                         strncpy(tmp->chan->musicclass, chan->musicclass, sizeof(tmp->chan->musicclass) - 1);
882                 if (chan->cid.cid_rdnis)
883                         tmp->chan->cid.cid_rdnis = strdup(chan->cid.cid_rdnis);
884                 /* Pass callingpres setting */
885                 tmp->chan->cid.cid_pres = chan->cid.cid_pres;
886                 /* Pass type of number */
887                 tmp->chan->cid.cid_ton = chan->cid.cid_ton;
888                 /* Pass type of tns */
889                 tmp->chan->cid.cid_tns = chan->cid.cid_tns;
890                 /* Presense of ADSI CPE on outgoing channel follows ours */
891                 tmp->chan->adsicpe = chan->adsicpe;
892                 /* pass the digital flag */
893                 ast_dup_flag(tmp->chan, chan, AST_FLAG_DIGITAL);
894
895                 /* If we have an outbound group, set this peer channel to it */
896                 if (outbound_group)
897                         ast_app_group_set_channel(tmp->chan, outbound_group);
898
899                 /* Place the call, but don't wait on the answer */
900                 res = ast_call(tmp->chan, numsubst, 0);
901
902                 /* Save the info in cdr's that we called them */
903                 if (chan->cdr)
904                         ast_cdr_setdestchan(chan->cdr, tmp->chan->name);
905
906                 /* check the results of ast_call */
907                 if (res) {
908                         /* Again, keep going even if there's an error */
909                         if (option_debug)
910                                 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
911                         else if (option_verbose > 2)
912                                 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", numsubst);
913                         ast_hangup(tmp->chan);
914                         tmp->chan = NULL;
915                         cur = rest;
916                         continue;
917                 } else
918                         if (option_verbose > 2)
919                                 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", numsubst);
920                 /* Put them in the list of outgoing thingies...  We're ready now. 
921                    XXX If we're forcibly removed, these outgoing calls won't get
922                    hung up XXX */
923                 tmp->stillgoing = -1;
924                 tmp->next = outgoing;
925                 outgoing = tmp;
926                 /* If this line is up, don't try anybody else */
927                 if (outgoing->chan->_state == AST_STATE_UP)
928                         break;
929                 cur = rest;
930         } while(cur);
931         
932         if (timeout && !ast_strlen_zero(timeout)) {
933                 to = atoi(timeout);
934                 if (to > 0)
935                         to *= 1000;
936                 else
937                         ast_log(LOG_WARNING, "Invalid timeout specified: '%s'\n", timeout);
938         } else
939                 to = -1;
940
941         if (outgoing) {
942                 /* Our status will at least be NOANSWER */
943                 strncpy(status, "NOANSWER", sizeof(status) - 1);
944                 if (outgoing->musiconhold) {
945                         moh=1;
946                         ast_moh_start(chan, NULL);
947                 } else if (outgoing->ringbackonly) {
948                         ast_indicate(chan, AST_CONTROL_RINGING);
949                         sentringing++;
950                 }
951         } else
952                 strncpy(status, "CHANUNAVAIL", sizeof(status) - 1);
953
954         time(&start_time);
955         peer = wait_for_answer(chan, outgoing, &to, &allowredir_in, &allowredir_out, &allowdisconnect_in, &allowdisconnect_out, &sentringing, status, sizeof(status), numbusy, numnochan, numcongestion);
956
957         if (!peer) {
958                 if (to) 
959                         /* Musta gotten hung up */
960                         res = -1;
961                  else 
962                         /* Nobody answered, next please? */
963                         res=0;
964                 
965                 goto out;
966         }
967         if (peer) {
968                 time(&answer_time);
969 #ifdef OSP_SUPPORT
970                 /* Once call is answered, ditch the OSP Handle */
971                 pbx_builtin_setvar_helper(chan, "OSPHANDLE", "");
972 #endif          
973                 strncpy(status, "ANSWER", sizeof(status) - 1);
974                 /* Ah ha!  Someone answered within the desired timeframe.  Of course after this
975                    we will always return with -1 so that it is hung up properly after the 
976                    conversation.  */
977                 hanguptree(outgoing, peer);
978                 outgoing = NULL;
979                 /* If appropriate, log that we have a destination channel */
980                 if (chan->cdr)
981                         ast_cdr_setdestchan(chan->cdr, peer->name);
982                 if (peer->name)
983                         pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", peer->name);
984                 if (numsubst)
985                         pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", numsubst);
986                 /* JDG: sendurl */
987                 if( url && !ast_strlen_zero(url) && ast_channel_supports_html(peer) ) {
988                         ast_log(LOG_DEBUG, "app_dial: sendurl=%s.\n", url);
989                         ast_channel_sendurl( peer, url );
990                 } /* /JDG */
991                 if (announce && announcemsg) {
992                         // Start autoservice on the other chan
993                         res = ast_autoservice_start(chan);
994                         // Now Stream the File
995                         if (!res)
996                                 res = ast_streamfile(peer,announcemsg,peer->language);
997                         if (!res) {
998                                 digit = ast_waitstream(peer, AST_DIGIT_ANY); 
999                         }
1000                         // Ok, done. stop autoservice
1001                         res = ast_autoservice_stop(chan);
1002                         if (digit > 0 && !res)
1003                                 res = ast_senddigit(chan, digit); 
1004                         else
1005                                 res = digit;
1006
1007                 } else
1008                         res = 0;
1009
1010                 if (hasmacro && macroname) {
1011                         res = ast_autoservice_start(chan);
1012                         if (res) {
1013                                 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
1014                                 res = -1;
1015                         }
1016
1017                         app = pbx_findapp("Macro");
1018
1019                         if (app && !res) {
1020                                 for(res=0;res<strlen(macroname);res++)
1021                                         if(macroname[res] == '^')
1022                                                 macroname[res] = '|';
1023                                 res = pbx_exec(peer, app, macroname, 1);
1024                                 ast_log(LOG_DEBUG, "Macro exited with status %d\n", res);
1025                                 res = 0;
1026                         } else {
1027                                 ast_log(LOG_ERROR, "Could not find application Macro\n");
1028                                 res = -1;
1029                         }
1030
1031                         if (ast_autoservice_stop(chan) < 0) {
1032                                 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
1033                                 res = -1;
1034                         }
1035
1036                         if (!res) {
1037                                 if ((macro_result = pbx_builtin_getvar_helper(peer, "MACRO_RESULT"))) {
1038                                         if (!strcasecmp(macro_result, "BUSY")) {
1039                                                 strncpy(status, macro_result, sizeof(status) - 1);
1040                                                 if (!ast_goto_if_exists(chan, NULL, NULL, chan->priority + 101)) {
1041                                                         go_on = 1;
1042                                                 }
1043                                                 res = -1;
1044                                         }
1045                                         else if (!strcasecmp(macro_result, "CONGESTION") || !strcasecmp(macro_result, "CHANUNAVAIL")) {
1046                                                 strncpy(status, macro_result, sizeof(status) - 1);
1047                                                 go_on = 1;
1048                                                 res = -1;
1049                                         }
1050                                         else if (!strcasecmp(macro_result, "CONTINUE")) {
1051                                                 /* hangup peer and keep chan alive assuming the macro has changed 
1052                                                    the context / exten / priority or perhaps 
1053                                                    the next priority in the current exten is desired.
1054                                                 */
1055                                                 go_on = 1;
1056                                                 res = -1;
1057                                         } else if (!strcasecmp(macro_result, "ABORT")) {
1058                                                 /* Hangup both ends unless the caller has the g flag */
1059                                                 res = -1;
1060                                         } else if(!strncasecmp(macro_result, "GOTO:",5) && (macro_transfer_dest = ast_strdupa(macro_result + 5))) {
1061                                                 res = -1;
1062                                                 /* perform a transfer to a new extension */
1063                                                 if(strchr(macro_transfer_dest,'^')) { /* context^exten^priority*/
1064                                                         /* no brainer mode... substitute ^ with | and feed it to builtin goto */
1065                                                         for(res=0;res<strlen(macro_transfer_dest);res++)
1066                                                                 if(macro_transfer_dest[res] == '^')
1067                                                                         macro_transfer_dest[res] = '|';
1068
1069                                                         if(!ast_parseable_goto(chan, macro_transfer_dest))
1070                                                                 go_on = 1;
1071                                                         
1072                                                 }
1073                                         }
1074                                 }
1075                         }
1076                 }
1077
1078                 if (!res) {
1079                         if (calldurationlimit > 0) {
1080                                 time(&now);
1081                                 chan->whentohangup = now + calldurationlimit;
1082                         }
1083                         if (!ast_strlen_zero(sdtmfdata)) 
1084                                 res = ast_dtmf_stream(peer,chan,sdtmfdata,250);
1085                 }
1086                 
1087                 if (!res) {
1088                         memset(&config,0,sizeof(struct ast_bridge_config));
1089                         config.play_to_caller=play_to_caller;
1090                         config.play_to_callee=play_to_callee;
1091                         config.allowredirect_in = allowredir_in;
1092                         config.allowredirect_out = allowredir_out;
1093                         config.allowdisconnect_in = allowdisconnect_in;
1094                         config.allowdisconnect_out = allowdisconnect_out;
1095                         config.timelimit = timelimit;
1096                         config.play_warning = play_warning;
1097                         config.warning_freq = warning_freq;
1098                         config.warning_sound = warning_sound;
1099                         config.end_sound = end_sound;
1100                         config.start_sound = start_sound;
1101                         if (moh) {
1102                                 moh = 0;
1103                                 ast_moh_stop(chan);
1104                         } else if (sentringing) {
1105                                 sentringing = 0;
1106                                 ast_indicate(chan, -1);
1107                         }
1108                         /* Be sure no generators are left on it */
1109                         ast_deactivate_generator(chan);
1110                         /* Make sure channels are compatible */
1111                         res = ast_channel_make_compatible(chan, peer);
1112                         if (res < 0) {
1113                                 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", chan->name, peer->name);
1114                                 ast_hangup(peer);
1115                                 return -1;
1116                         }
1117                         res = ast_bridge_call(chan,peer,&config);
1118                         time(&end_time);
1119                         snprintf(toast, sizeof(toast), "%ld", (long)(end_time - start_time));
1120                         pbx_builtin_setvar_helper(chan, "DIALEDTIME", toast);
1121                         snprintf(toast, sizeof(toast), "%ld", (long)(end_time - answer_time));
1122                         pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", toast);
1123                         
1124                 } else 
1125                         res = -1;
1126                 
1127                 if (res != AST_PBX_NO_HANGUP_PEER) {
1128                         if (!chan->_softhangup)
1129                                 chan->hangupcause = peer->hangupcause;
1130                         ast_hangup(peer);
1131                 }
1132         }       
1133 out:
1134         if (moh) {
1135                 moh = 0;
1136                 ast_moh_stop(chan);
1137         } else if (sentringing) {
1138                 sentringing = 0;
1139                 ast_indicate(chan, -1);
1140         }
1141         hanguptree(outgoing, NULL);
1142         pbx_builtin_setvar_helper(chan, "DIALSTATUS", status);
1143         ast_log(LOG_DEBUG, "Exiting with DIALSTATUS=%s.\n", status);
1144         
1145         LOCAL_USER_REMOVE(u);
1146         
1147         if((go_on>0) && (!chan->_softhangup))
1148             res=0;
1149             
1150         return res;
1151 }
1152
1153 int unload_module(void)
1154 {
1155         STANDARD_HANGUP_LOCALUSERS;
1156         return ast_unregister_application(app);
1157 }
1158
1159 int load_module(void)
1160 {
1161         int res;
1162         res = ast_register_application(app, dial_exec, synopsis, descrip);
1163         return res;
1164 }
1165
1166 char *description(void)
1167 {
1168         return tdesc;
1169 }
1170
1171 int usecount(void)
1172 {
1173         int res;
1174         STANDARD_USECOUNT(res);
1175         return res;
1176 }
1177
1178 char *key()
1179 {
1180         return ASTERISK_GPL_KEY;
1181 }