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