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