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