6cbd9c32f1824f2f64b9c7e1220f1fc8f5103024
[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, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
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/parking.h>
24 #include <asterisk/musiconhold.h>
25 #include <asterisk/callerid.h>
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <sys/time.h>
33 #include <sys/signal.h>
34 #include <netinet/in.h>
35
36 #include <pthread.h>
37
38 static char *tdesc = "Dialing Application";
39
40 static char *app = "Dial";
41
42 static char *synopsis = "Place an call and connect to the current channel";
43
44 static char *descrip =
45 "  Dial(Technology/resource[&Technology2/resource2...][|timeout][|options][|URL]):\n"
46 "Requests  one  or more channels and places specified outgoing calls on them.\n"
47 "As soon as a  channel  answers, the  Dial  app  will  answer the originating\n"
48 "channel (if it needs to be answered) and will bridge a call with the channel\n"
49 "which first answered. All other calls placed by the Dial app will be hunp up\n"
50 "If a timeout is not specified, the Dial  application  will wait indefinitely\n"
51 "until either one of the  called channels  answers, the user hangs up, or all\n"
52 "channels return busy or  error. In general,  the dialler will return 0 if it\n"
53 "was  unable  to  place  the  call, or the timeout expired.  However, if  all\n"
54 "channels were busy, and there exists an extension with priority n+101 (where\n"
55 "n is the priority of  the  dialler  instance), then  it  will  be  the  next\n"
56 "executed extension (this allows you to setup different behavior on busy from\n"
57 "no-answer).\n"
58 "  This application returns -1 if the originating channel hangs up, or if the\n"
59 "call is bridged and  either of the parties in the bridge terminate the call.\n"
60 "The option string may contain zero or more of the following characters:\n"
61 "      't' -- allow the called user transfer the calling user\n"
62 "      'T' -- to allow the calling user to transfer the call.\n"
63 "      'r' -- indicate ringing to the calling party, pass no audio until answered.\n"
64 "      'm' -- provide hold music to the calling party until answered.\n"
65 "      'd' -- data-quality (modem) call (minimum delay).\n"
66 "      'c' -- clear-channel data call (PRI-PRI only).\n"
67 "      'H' -- allow caller to hang up by hitting *.\n"
68 "      'C' -- reset call detail record for this call.\n"
69 "      'P[(x)]' -- privacy mode, using 'x' as database if provided.\n"
70 "  In addition to transferring the call, a call may be parked and then picked\n"
71 "up by another user.\n"
72 "  The optionnal URL will be sent to the called party if the channel supports\n"
73 "it.\n";
74
75 /* We define a customer "local user" structure because we
76    use it not only for keeping track of what is in use but
77    also for keeping track of who we're dialing. */
78
79 struct localuser {
80         struct ast_channel *chan;
81         int stillgoing;
82         int allowredirect_in;
83         int allowredirect_out;
84         int ringbackonly;
85         int musiconhold;
86         int dataquality;
87         int allowdisconnect;
88         struct localuser *next;
89 };
90
91 LOCAL_USER_DECL;
92
93 static void hanguptree(struct localuser *outgoing, struct ast_channel *exception)
94 {
95         /* Hang up a tree of stuff */
96         struct localuser *oo;
97         while(outgoing) {
98                 /* Hangup any existing lines we have open */
99                 if (outgoing->chan && (outgoing->chan != exception))
100                         ast_hangup(outgoing->chan);
101                 oo = outgoing;
102                 outgoing=outgoing->next;
103                 free(oo);
104         }
105 }
106
107 #define MAX 256
108
109 static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localuser *outgoing, int *to, int *allowredir_in, int *allowredir_out, int *allowdisconnect)
110 {
111         struct localuser *o;
112         int found;
113         int numlines;
114         int sentringing = 0;
115         int numbusies = 0;
116         int orig = *to;
117         struct ast_frame *f;
118         struct ast_channel *peer = NULL;
119         struct ast_channel *watchers[MAX];
120         int pos;
121         int single;
122         int moh=0;
123         int ringind=0;
124         struct ast_channel *winner;
125         
126         single = (outgoing && !outgoing->next && !outgoing->musiconhold && !outgoing->ringbackonly);
127         
128         if (single) {
129                 /* If we are calling a single channel, make them compatible for in-band tone purpose */
130                 ast_channel_make_compatible(outgoing->chan, in);
131         }
132         
133         if (outgoing) {
134                 moh = outgoing->musiconhold;
135                 ringind = outgoing->ringbackonly;
136                 if (outgoing->musiconhold) {
137                         ast_moh_start(in, NULL);
138                 } else if (outgoing->ringbackonly) {
139                         ast_indicate(in, AST_CONTROL_RINGING);
140                 }
141         }
142         
143         while(*to && !peer) {
144                 o = outgoing;
145                 found = -1;
146                 pos = 1;
147                 numlines = 0;
148                 watchers[0] = in;
149                 while(o) {
150                         /* Keep track of important channels */
151                         if (o->stillgoing && o->chan) {
152                                 watchers[pos++] = o->chan;
153                                 found = 1;
154                         }
155                         o = o->next;
156                         numlines++;
157                 }
158                 if (found < 0) {
159                         if (numlines == numbusies) {
160                                 if (option_verbose > 2)
161                                         ast_verbose( VERBOSE_PREFIX_2 "Everyone is busy at this time\n");
162                                 /* See if there is a special busy message */
163                                 if (ast_exists_extension(in, in->context, in->exten, in->priority + 101, in->callerid)) 
164                                         in->priority+=100;
165                         } else {
166                                 if (option_verbose > 2)
167                                         ast_verbose( VERBOSE_PREFIX_2 "No one is available to answer at this time\n");
168                         }
169                         *to = 0;
170                         /* if no one available we'd better stop MOH/ringing to */
171                         if (moh) {
172                                 ast_moh_stop(in);
173                         } else if (ringind) {
174                                 ast_indicate(in, -1);
175                         }
176                         return NULL;
177                 }
178                 winner = ast_waitfor_n(watchers, pos, to);
179                 o = outgoing;
180                 while(o) {
181                         if (o->stillgoing && o->chan && (o->chan->_state == AST_STATE_UP)) {
182                                 if (!peer) {
183                                         if (option_verbose > 2)
184                                                 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
185                                         peer = o->chan;
186                                         *allowredir_in = o->allowredirect_in;
187                                         *allowredir_out = o->allowredirect_out;
188                                         *allowdisconnect = o->allowdisconnect;
189                                 }
190                         } else if (o->chan && (o->chan == winner)) {
191                                 if (strlen(o->chan->call_forward)) {
192                                         char tmpchan[256];
193                                         /* Before processing channel, go ahead and check for forwarding */
194                                         if (option_verbose > 2)
195                                                 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s@%s' (thanks to %s)\n", in->name, o->chan->call_forward, o->chan->context, o->chan->name);
196                                         /* Setup parameters */
197                                         snprintf(tmpchan, sizeof(tmpchan),"%s@%s", o->chan->call_forward, o->chan->context);
198                                         ast_hangup(o->chan);
199                                         o->chan = ast_request("Local", in->nativeformats, tmpchan);
200                                         if (!o->chan) {
201                                                 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s'\n", tmpchan);
202                                                 o->stillgoing = 0;
203                                                 numbusies++;
204                                         } else if (ast_call(o->chan, tmpchan, 0)) {
205                                                 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
206                                                 o->stillgoing = 0;
207                                                 ast_hangup(o->chan);
208                                                 o->chan = NULL;
209                                                 numbusies++;
210                                         }
211                                         continue;
212                                 }
213                                 f = ast_read(winner);
214                                 if (f) {
215                                         if (f->frametype == AST_FRAME_CONTROL) {
216                                                 switch(f->subclass) {
217                                             case AST_CONTROL_ANSWER:
218                                                         /* This is our guy if someone answered. */
219                                                         if (!peer) {
220                                                                 if (option_verbose > 2)
221                                                                         ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
222                                                                 peer = o->chan;
223                                                                 *allowredir_in = o->allowredirect_in;
224                                                                 *allowredir_out = o->allowredirect_out;
225                                                                 *allowdisconnect = o->allowdisconnect;
226                                                         }
227                                                         break;
228                                                 case AST_CONTROL_BUSY:
229                                                         if (option_verbose > 2)
230                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
231                                                         ast_hangup(o->chan);
232                                                         o->chan = NULL;
233                                                         o->stillgoing = 0;
234                                                         if (in->cdr)
235                                                                 ast_cdr_busy(in->cdr);
236                                                         numbusies++;
237                                                         break;
238                                                 case AST_CONTROL_CONGESTION:
239                                                         if (option_verbose > 2)
240                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
241                                                         ast_hangup(o->chan);
242                                                         o->chan = NULL;
243                                                         o->stillgoing = 0;
244                                                         if (in->cdr)
245                                                                 ast_cdr_busy(in->cdr);
246                                                         numbusies++;
247                                                         break;
248                                                 case AST_CONTROL_RINGING:
249                                                         if (option_verbose > 2)
250                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
251                                                         if (!sentringing && !moh) {
252                                                                 ast_indicate(in, AST_CONTROL_RINGING);
253                                                                 sentringing++;
254                                                                 ringind++;
255                                                         }
256                                                         break;
257                                                 case AST_CONTROL_PROGRESS:
258                                                         if (option_verbose > 2)
259                                                                 ast_verbose ( VERBOSE_PREFIX_3 "%s is making progress passing it to %s\n", o->chan->name,in->name);
260                                                         ast_indicate(in, AST_CONTROL_PROGRESS);
261                                                         break;
262                                                 case AST_CONTROL_OFFHOOK:
263                                                         /* Ignore going off hook */
264                                                         break;
265                                                 case -1:
266                                                         if (option_verbose > 2)
267                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s stopped sounds\n", o->chan->name);
268                                                         ast_indicate(in, -1);
269                                                         break;
270                                                 default:
271                                                         ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
272                                                 }
273                                         } else if (single && (f->frametype == AST_FRAME_VOICE) && 
274                                                                 !(outgoing->ringbackonly || outgoing->musiconhold)) {
275                                                 if (ast_write(in, f)) 
276                                                         ast_log(LOG_WARNING, "Unable to forward frame\n");
277                                         } else if (single && (f->frametype == AST_FRAME_IMAGE) && 
278                                                                 !(outgoing->ringbackonly || outgoing->musiconhold)) {
279                                                 if (ast_write(in, f))
280                                                         ast_log(LOG_WARNING, "Unable to forward image\n");
281                                         }
282                                         ast_frfree(f);
283                                 } else {
284                                         ast_hangup(o->chan);
285                                         o->chan = NULL;
286                                         o->stillgoing = 0;
287                                 }
288                         }
289                         o = o->next;
290                 }
291                 if (winner == in) {
292                         f = ast_read(in);
293 #if 0
294                         if (f && (f->frametype != AST_FRAME_VOICE))
295                                         printf("Frame type: %d, %d\n", f->frametype, f->subclass);
296                         else if (!f || (f->frametype != AST_FRAME_VOICE))
297                                 printf("Hangup received on %s\n", in->name);
298 #endif
299                         if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
300                                 /* Got hung up */
301                                 *to=-1;
302                                 return NULL;
303                         }
304                         if (f && (f->frametype == AST_FRAME_DTMF) && *allowdisconnect &&
305                                 (f->subclass == '*')) {
306                             if (option_verbose > 3)
307                                 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
308                                 *to=0;
309                                 return NULL;
310                         }
311                         if (single && ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_DTMF)))  {
312                                 if (ast_write(outgoing->chan, f))
313                                         ast_log(LOG_WARNING, "Unable to forward voice\n");
314                                 ast_frfree(f);
315                         }
316                 }
317                 if (!*to && (option_verbose > 2))
318                         ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
319         }
320         if (moh) {
321                 ast_moh_stop(in);
322         } else if (ringind) {
323                 ast_indicate(in, -1);
324         }
325
326         return peer;
327         
328 }
329
330 static int dial_exec(struct ast_channel *chan, void *data)
331 {
332         int res=-1;
333         struct localuser *u;
334         char info[256], *peers, *timeout, *tech, *number, *rest, *cur;
335         char  privdb[256] = "", *s;
336         struct localuser *outgoing=NULL, *tmp;
337         struct ast_channel *peer;
338         int to;
339         int allowredir_in=0;
340         int allowredir_out=0;
341         int allowdisconnect=0;
342         int privacy=0;
343         int resetcdr=0;
344         int clearchannel=0;
345         char numsubst[AST_MAX_EXTENSION];
346         char restofit[AST_MAX_EXTENSION];
347         char *transfer = NULL;
348         char *newnum;
349         char callerid[256], *l, *n;
350         char *url=NULL; /* JDG */
351         struct ast_var_t *current;
352         struct varshead *headp, *newheadp;
353         struct ast_var_t *newvar;
354         
355         if (!data) {
356                 ast_log(LOG_WARNING, "Dial requires an argument (technology1/number1&technology2/number2...|optional timeout)\n");
357                 return -1;
358         }
359         
360         LOCAL_USER_ADD(u);
361         
362         /* Parse our arguments XXX Check for failure XXX */
363         strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
364         peers = info;
365         if (peers) {
366                 timeout = strchr(info, '|');
367                 if (timeout) {
368                         *timeout = '\0';
369                         timeout++;
370                         transfer = strchr(timeout, '|');
371                         if (transfer) {
372                                 *transfer = '\0';
373                                 transfer++;
374                                 /* JDG */
375                                 url = strchr(transfer, '|');
376                                 if (url) {
377                                         *url = '\0';
378                                         url++;
379                                         ast_log(LOG_DEBUG, "DIAL WITH URL=%s_\n", url);
380                                 } else 
381                                         ast_log(LOG_DEBUG, "SIMPLE DIAL (NO URL)\n");
382                                 /* /JDG */
383                         }
384                 }
385         } else
386                 timeout = NULL;
387         if (!peers || !strlen(peers)) {
388                 ast_log(LOG_WARNING, "Dial argument takes format (technology1/number1&technology2/number2...|optional timeout)\n");
389                 goto out;
390         }
391         
392
393         if (transfer) {
394                 /* Extract privacy info from transfer */
395                 if ((s = strstr(transfer, "P("))) {
396                         privacy = 1;
397                         strncpy(privdb, s + 2, sizeof(privdb) - 1);
398                         /* Overwrite with X's what was the privacy info */
399                         while(*s && (*s != ')')) 
400                                 *(s++) = 'X';
401                         if (*s)
402                                 *s = 'X';
403                         /* Now find the end of the privdb */
404                         s = strchr(privdb, ')');
405                         if (s)
406                                 *s = '\0';
407                         else {
408                                 ast_log(LOG_WARNING, "Transfer with privacy lacking trailing '('\n");
409                                 privacy = 0;
410                         }
411                 } else if (strchr(transfer, 'P')) {
412                         /* No specified privdb */
413                         privacy = 1;
414                 } else if (strchr(transfer, 'C')) {
415                         resetcdr = 1;
416                 }
417         }
418         if (resetcdr && chan->cdr)
419                 ast_cdr_reset(chan->cdr, 0);
420         if (!strlen(privdb) && privacy) {
421                 /* If privdb is not specified and we are using privacy, copy from extension */
422                 strncpy(privdb, chan->exten, sizeof(privdb) - 1);
423         }
424         if (privacy) {
425                 if (chan->callerid)
426                         strncpy(callerid, chan->callerid, sizeof(callerid));
427                 else
428                         strcpy(callerid, "");
429                 ast_callerid_parse(callerid, &n, &l);
430                 if (l) {
431                         ast_shrink_phone_number(l);
432                 } else
433                         l = "";
434                 ast_log(LOG_NOTICE, "Privacy DB is '%s', privacy is %d, clid is '%s'\n", privdb, privacy, l);
435         }
436         cur = peers;
437         do {
438                 /* Remember where to start next time */
439                 rest = strchr(cur, '&');
440                 if (rest) {
441                         *rest = 0;
442                         rest++;
443                 }
444                 /* Get a technology/[device:]number pair */
445                 tech = cur;
446                 number = strchr(tech, '/');
447                 if (!number) {
448                         ast_log(LOG_WARNING, "Dial argument takes format (technology1/[device:]number1&technology2/[device:]number2...|optional timeout)\n");
449                         goto out;
450                 }
451                 *number = '\0';
452                 number++;
453                 tmp = malloc(sizeof(struct localuser));
454                 if (!tmp) {
455                         ast_log(LOG_WARNING, "Out of memory\n");
456                         goto out;
457                 }
458                 memset(tmp, 0, sizeof(struct localuser));
459                 if (transfer) {
460                         if (strchr(transfer, 't'))
461                                 tmp->allowredirect_in = 1;
462                         else    tmp->allowredirect_in = 0;
463                         if (strchr(transfer, 'T'))
464                                 tmp->allowredirect_out = 1;
465                         else    tmp->allowredirect_out = 0;
466                         if (strchr(transfer, 'r'))
467                                 tmp->ringbackonly = 1;
468                         else    tmp->ringbackonly = 0;
469                         if (strchr(transfer, 'm'))
470                                 tmp->musiconhold = 1;
471                         else    tmp->musiconhold = 0;
472                         if (strchr(transfer, 'd'))
473                                 tmp->dataquality = 1;
474                         else    tmp->dataquality = 0;
475                         if (strchr(transfer, 'H'))
476                                 allowdisconnect = tmp->allowdisconnect = 1;
477                         else    allowdisconnect = tmp->allowdisconnect = 0;
478                         if (strchr(transfer, 'c'))
479                                 clearchannel = 1;
480             else    
481                                 clearchannel = 0;
482                 }
483                 strncpy(numsubst, number, sizeof(numsubst)-1);
484                 /* If we're dialing by extension, look at the extension to know what to dial */
485                 if ((newnum = strstr(numsubst, "BYEXTENSION"))) {
486                         strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit)-1);
487                         snprintf(newnum, sizeof(numsubst) - (newnum - numsubst), "%s%s", chan->exten,restofit);
488                         if (option_debug)
489                                 ast_log(LOG_DEBUG, "Dialing by extension %s\n", numsubst);
490                 }
491                 /* Request the peer */
492                 tmp->chan = ast_request(tech, chan->nativeformats, numsubst);
493                 if (!tmp->chan) {
494                         /* If we can't, just go on to the next call */
495                         ast_log(LOG_NOTICE, "Unable to create channel of type '%s'\n", tech);
496                         if (chan->cdr)
497                                 ast_cdr_busy(chan->cdr);
498                         free(tmp);
499                         cur = rest;
500                         continue;
501                 }
502                 if (strlen(tmp->chan->call_forward)) {
503                         char tmpchan[256];
504                         if (option_verbose > 2)
505                                 ast_verbose(VERBOSE_PREFIX_3 "Forwarding call to '%s@%s'\n", tmp->chan->call_forward, tmp->chan->context);
506                         snprintf(tmpchan, sizeof(tmpchan),"%s@%s", tmp->chan->call_forward, tmp->chan->context);
507                         ast_hangup(tmp->chan);
508                         tmp->chan = ast_request("Local", chan->nativeformats, tmpchan);
509                         if (!tmp->chan) {
510                                 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s'\n", tmpchan);
511                                 free(tmp);
512                                 cur = rest;
513                                 continue;
514                         }
515                 }
516                 /* If creating a SIP channel, look for a variable called */
517                 /* VXML_URL in the calling channel and copy it to the    */
518                 /* new channel.                                          */
519                 if (strcasecmp(tech,"SIP")==0)
520                 {
521                         headp=&chan->varshead;
522                         AST_LIST_TRAVERSE(headp,current,entries) {
523                                 if (strcasecmp(ast_var_name(current),"VXML_URL")==0)
524                                 {
525                                         newvar=ast_var_assign(ast_var_name(current),ast_var_value(current));
526                                         newheadp=&tmp->chan->varshead;
527                                         AST_LIST_INSERT_HEAD(newheadp,newvar,entries);
528                                         break;
529                                 }
530                         }
531                 }
532                 /* Check for ALERT_INFO in the SetVar list.  This is for   */
533                 /* SIP distinctive ring as per the RFC.  For Cisco 7960s,  */
534                 /* SetVar(ALERT_INFO=<x>) where x is an integer.  However, */
535                 /* the RFC says it should be a URL.  -- km-                */
536
537                 if (strcasecmp(tech,"SIP")==0)
538                 {
539                         headp=&chan->varshead;
540                         AST_LIST_TRAVERSE(headp,current,entries) {
541                                 /* Search for ALERT_INFO */
542                                 if (strcasecmp(ast_var_name(current),"ALERT_INFO")==0)
543                                 {
544                                         newvar=ast_var_assign(ast_var_name(current),ast_var_value(current));
545                                         newheadp=&tmp->chan->varshead;
546                                         AST_LIST_INSERT_HEAD(newheadp,newvar,entries);
547                                         break;
548                                 }
549                         }
550                 }
551                 
552                 tmp->chan->appl = "AppDial";
553                 tmp->chan->data = "(Outgoing Line)";
554                 tmp->chan->whentohangup = 0;
555                 if (tmp->chan->callerid)
556                         free(tmp->chan->callerid);
557                 if (tmp->chan->ani)
558                         free(tmp->chan->ani);
559                 if (chan->callerid)
560                         tmp->chan->callerid = strdup(chan->callerid);
561                 else
562                         tmp->chan->callerid = NULL;
563                 if (chan->ani)
564                         tmp->chan->ani = strdup(chan->ani);
565                 else
566                         tmp->chan->ani = NULL;
567                 /* Presense of ADSI CPE on outgoing channel follows ours */
568                 tmp->chan->adsicpe = chan->adsicpe;
569                 /* Place the call, but don't wait on the answer */
570                 res = ast_call(tmp->chan, numsubst, 0);
571                 if (res) {
572                         /* Again, keep going even if there's an error */
573                         if (option_debug)
574                                 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
575                         else if (option_verbose > 2)
576                                 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", numsubst);
577                         ast_hangup(tmp->chan);
578                         free(tmp);
579                         cur = rest;
580                         continue;
581                 } else
582                         if (option_verbose > 2)
583                                 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", numsubst);
584                 /* Put them in the list of outgoing thingies...  We're ready now. 
585                    XXX If we're forcibly removed, these outgoing calls won't get
586                    hung up XXX */
587                 tmp->stillgoing = -1;
588                 tmp->next = outgoing;
589                 outgoing = tmp;
590                 /* If this line is up, don't try anybody else */
591                 if (outgoing->chan->_state == AST_STATE_UP)
592                         break;
593                 cur = rest;
594         } while(cur);
595         
596         if (timeout && strlen(timeout))
597                 to = atoi(timeout) * 1000;
598         else
599                 to = -1;
600         peer = wait_for_answer(chan, outgoing, &to, &allowredir_in, &allowredir_out, &allowdisconnect);
601         if (!peer) {
602                 if (to) 
603                         /* Musta gotten hung up */
604                         res = -1;
605                  else 
606                         /* Nobody answered, next please? */
607                         res=0;
608                 
609                 goto out;
610         }
611         if (peer) {
612                 /* Ah ha!  Someone answered within the desired timeframe.  Of course after this
613                    we will always return with -1 so that it is hung up properly after the 
614                    conversation.  */
615                 if (!strcmp(chan->type,"Zap"))
616                 {
617                         int x = 2;
618                         if (tmp->dataquality || clearchannel) x = 0;
619                         ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
620                 }                       
621                 if (!strcmp(peer->type,"Zap"))
622                 {
623                         int x = 2;
624                         if (tmp->dataquality || clearchannel) x = 0;
625                         ast_channel_setoption(peer,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
626                 }                       
627                 hanguptree(outgoing, peer);
628                 outgoing = NULL;
629                 /* If appropriate, log that we have a destination channel */
630                 if (chan->cdr)
631                         ast_cdr_setdestchan(chan->cdr, peer->name);
632                 if (peer->name)
633                         pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", peer->name);
634                 if (numsubst)
635                         pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", numsubst);
636                 /* Make sure channels are compatible */
637                 res = ast_channel_make_compatible(chan, peer);
638                 if (res < 0) {
639                         ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", chan->name, peer->name);
640                         ast_hangup(peer);
641                         return -1;
642                 }
643                 /* JDG: sendurl */
644                 if( url && strlen(url) && ast_channel_supports_html(peer) ) {
645                         ast_log(LOG_DEBUG, "app_dial: sendurl=%s.\n", url);
646                         ast_channel_sendurl( peer, url );
647                 } /* /JDG */
648                 if (clearchannel)
649                 {
650                         int x = 0;
651                         ast_channel_setoption(chan,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
652                         ast_channel_setoption(peer,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
653                 }
654                 res = ast_bridge_call(chan, peer, allowredir_in, allowredir_out, allowdisconnect | clearchannel);
655                 if (clearchannel)
656                 {
657                         int x = 1;
658                         ast_channel_setoption(chan,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
659                         ast_channel_setoption(peer,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
660                 }
661
662                 if (res != AST_PBX_NO_HANGUP_PEER)
663                         ast_hangup(peer);
664         }       
665 out:
666         hanguptree(outgoing, NULL);
667         LOCAL_USER_REMOVE(u);
668         return res;
669 }
670
671 int unload_module(void)
672 {
673         STANDARD_HANGUP_LOCALUSERS;
674         return ast_unregister_application(app);
675 }
676
677 int load_module(void)
678 {
679         int res;
680         res = ast_register_application(app, dial_exec, synopsis, descrip);
681         return res;
682 }
683
684 char *description(void)
685 {
686         return tdesc;
687 }
688
689 int usecount(void)
690 {
691         int res;
692         STANDARD_USECOUNT(res);
693         return res;
694 }
695
696 char *key()
697 {
698         return ASTERISK_GPL_KEY;
699 }