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