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