2 * Asterisk -- A telephony toolkit for Linux.
4 * Trivial application to dial a channel and send an URL on answer
6 * Copyright (C) 1999 - 2005, Digium, Inc.
8 * Mark Spencer <markster@digium.com>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
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 <asterisk/manager.h>
38 #include <sys/signal.h>
39 #include <netinet/in.h>
41 static char *tdesc = "Dialing Application";
43 static char *app = "Dial";
45 static char *synopsis = "Place a call and connect to the current channel";
47 static char *descrip =
48 " Dial(Technology/resource[&Technology2/resource2...][|timeout][|options][|URL]):\n"
49 "Requests one or more channels and places specified outgoing calls on them.\n"
50 "As soon as a channel answers, the Dial app will answer the originating\n"
51 "channel (if it needs to be answered) and will bridge a call with the channel\n"
52 "which first answered. All other calls placed by the Dial app will be hung up.\n"
53 "If a timeout is not specified, the Dial application will wait indefinitely\n"
54 "until either one of the called channels answers, the user hangs up, or all\n"
55 "channels return busy or error. In general, the dialer will return 0 if it\n"
56 "was unable to place the call, or the timeout expired. However, if all\n"
57 "channels were busy, and there exists an extension with priority n+101 (where\n"
58 "n is the priority of the dialer instance), then it will be the next\n"
59 "executed extension (this allows you to setup different behavior on busy from\n"
61 " This application returns -1 if the originating channel hangs up, or if the\n"
62 "call is bridged and either of the parties in the bridge terminate the call.\n"
63 "The option string may contain zero or more of the following characters:\n"
64 " 'd' -- allow the calling user to dial a 1 digit extension while waiting for a call to\n"
65 " be answered exiting to that extension if it exists in the context defined by\n"
66 " ${EXITCONTEXT} or the current context.\n"
67 " 't' -- allow the called user to transfer the calling user by hitting #.\n"
68 " 'T' -- allow the calling user to transfer the call by hitting #.\n"
69 " 'w' -- allow the called user to write the conversation to disk via app_monitor\n"
70 " 'W' -- allow the calling user to write the conversation to disk via app_monitor\n"
71 " 'f' -- Forces callerid to be set as the extension of the line \n"
72 " making/redirecting the outgoing call. For example, some PSTNs\n"
73 " don't allow callerids from other extensions then the ones\n"
74 " that are assigned to you.\n"
75 " 'o' -- Original (inbound) Caller*ID should be placed on the outbound leg of the call\n"
76 " instead of using the destination extension (old style asterisk behavior)\n"
77 " 'r' -- indicate ringing to the calling party, pass no audio until answered.\n"
78 " 'm[(class)]' -- provide hold music to the calling party until answered (optionally\n"
79 " with the specified class.\n"
80 " 'M(x[^arg]) -- Executes the macro (x with ^ delim arg list) upon connect of the call.\n"
81 " Also, the macro can set the MACRO_RESULT variable to do the following:\n"
82 " -- ABORT - Hangup both legs of the call.\n"
83 " -- CONGESTION - Behave as if line congestion was encountered.\n"
84 " -- BUSY - Behave as if a busy signal was encountered. (n+101)\n"
85 " -- CONTINUE - Hangup the called party and continue on in the dialplan.\n"
86 " -- GOTO:<context>^<exten>^<priority> - Transfer the call.\n"
87 " 'h' -- allow callee to hang up by hitting *.\n"
88 " 'H' -- allow caller to hang up by hitting *.\n"
89 " 'C' -- reset call detail record for this call.\n"
90 " 'P[(x)]' -- privacy mode, using 'x' as database if provided.\n"
91 " 'g' -- goes on in context if the destination channel hangs up\n"
92 " 'A(x)' -- play an announcement to the called party, using x as file\n"
93 " 'S(x)' -- hangup the call after x seconds AFTER called party picked up\n"
94 " 'D([digits])' -- Send DTMF digit string *after* called party has answered\n"
95 " but before the bridge. (w=500ms sec pause)\n"
96 " 'L(x[:y][:z])' -- Limit the call to 'x' ms warning when 'y' ms are left\n"
97 " repeated every 'z' ms) Only 'x' is required, 'y' and 'z' are optional.\n"
98 " The following special variables are optional:\n"
99 " * LIMIT_PLAYAUDIO_CALLER yes|no (default yes)\n"
100 " Play sounds to the caller.\n"
101 " * LIMIT_PLAYAUDIO_CALLEE yes|no\n"
102 " Play sounds to the callee.\n"
103 " * LIMIT_TIMEOUT_FILE File to play when time is up.\n"
104 " * LIMIT_CONNECT_FILE File to play when call begins.\n"
105 " * LIMIT_WARNING_FILE File to play as warning if 'y' is defined.\n"
106 " 'timeleft' is a special sound macro to auto-say the time \n"
107 " left and is the default.\n\n"
108 " In addition to transferring the call, a call may be parked and then picked\n"
109 "up by another user.\n"
110 " The optional URL will be sent to the called party if the channel supports it.\n"
111 " If the OUTBOUND_GROUP variable is set, all peer channels created by this\n"
112 " application will be put into that group (as in SetGroup).\n"
113 " This application sets the following channel variables upon completion:\n"
114 " DIALEDTIME Time from dial to answer\n"
115 " ANSWEREDTIME Time for actual call\n"
116 " DIALSTATUS The status of the call as a text string, one of\n"
117 " CHANUNAVAIL | CONGESTION | NOANSWER | BUSY | ANSWER | CANCEL\n"
120 /* RetryDial App by Anthony Minessale II <anthmct@yahoo.com> Jan/2005 */
121 static char *rapp = "RetryDial";
122 static char *rsynopsis = "Place a call, retrying on failure allowing optional exit extension.\n";
123 static char *rdescrip =
124 " RetryDial(announce|sleep|loops|Technology/resource[&Technology2/resource2...][|timeout][|options][|URL]):\n"
125 "Attempt to place a call. If no channel can be reached, play the file defined by 'announce'\n"
126 "waiting 'sleep' seconds to retry the call. If the specified number of attempts matches \n"
127 "'loops' the call will continue in the dialplan. If 'loops' is set to 0, the call will retry endlessly.\n\n"
128 "While waiting, a 1 digit extension may be dialed. If that extension exists in either\n"
129 "the context defined in ${EXITCONTEXT} or the current one, The call will transfer\n"
130 "to that extension immmediately.\n\n"
131 "All arguments after 'loops' are passed directly to the Dial() application.\n"
135 /* We define a customer "local user" structure because we
136 use it not only for keeping track of what is in use but
137 also for keeping track of who we're dialing. */
139 #define DIAL_STILLGOING (1 << 0)
140 #define DIAL_ALLOWREDIRECT_IN (1 << 1)
141 #define DIAL_ALLOWREDIRECT_OUT (1 << 2)
142 #define DIAL_ALLOWDISCONNECT_IN (1 << 3)
143 #define DIAL_ALLOWDISCONNECT_OUT (1 << 4)
144 #define DIAL_RINGBACKONLY (1 << 5)
145 #define DIAL_MUSICONHOLD (1 << 6)
146 #define DIAL_FORCECALLERID (1 << 7)
147 #define DIAL_MONITOR_IN (1 << 8)
148 #define DIAL_MONITOR_OUT (1 << 9)
149 #define DIAL_GO_ON (1 << 10)
150 #define DIAL_HALT_ON_DTMF (1 << 11)
151 #define DIAL_PRESERVE_CALLERID (1 << 12)
152 #define DIAL_NOFORWARDHTML (1 << 13)
155 struct ast_channel *chan;
158 struct localuser *next;
163 static void hanguptree(struct localuser *outgoing, struct ast_channel *exception)
165 /* Hang up a tree of stuff */
166 struct localuser *oo;
168 /* Hangup any existing lines we have open */
169 if (outgoing->chan && (outgoing->chan != exception))
170 ast_hangup(outgoing->chan);
172 outgoing=outgoing->next;
177 #define AST_MAX_FORWARDS 8
179 #define AST_MAX_WATCHERS 256
181 #define HANDLE_CAUSE(cause, chan) do { \
183 case AST_CAUSE_BUSY: \
185 ast_cdr_busy(chan->cdr); \
188 case AST_CAUSE_CONGESTION: \
189 case AST_CAUSE_UNREGISTERED: \
191 ast_cdr_busy(chan->cdr); \
201 static int ast_onedigit_goto(struct ast_channel *chan, char *context, char exten, int pri, char *cid)
204 snprintf(rexten, 2, "%c", exten);
206 if (ast_exists_extension(chan, context, rexten, pri, cid)) {
207 ast_explicit_goto(chan, context, rexten, pri-1);
211 if (ast_exists_extension(chan, chan->context, rexten, pri, cid)) {
212 ast_explicit_goto(chan, chan->context, rexten, pri-1);
214 } else if (!ast_strlen_zero(chan->macrocontext)) {
215 if (ast_exists_extension(chan, chan->macrocontext, rexten, pri, cid)) {
216 ast_explicit_goto(chan, chan->macrocontext, rexten, pri-1);
225 static char *get_cid_name(char *name, int namelen, struct ast_channel *chan)
229 if (!ast_strlen_zero(chan->macrocontext))
230 context = chan->macrocontext;
232 context = chan->context;
234 if (!ast_strlen_zero(chan->macroexten))
235 exten = chan->macroexten;
239 if (ast_get_hint(NULL, 0, name, namelen, chan, context, exten))
245 static void senddialevent(struct ast_channel *src, struct ast_channel *dst)
247 manager_event(EVENT_FLAG_CALL, "Dial",
249 "Destination: %s\r\n"
251 "CallerIDName: %s\r\n"
252 "SrcUniqueID: %s\r\n"
253 "DestUniqueID: %s\r\n",
254 src->name, dst->name, src->cid.cid_num ? src->cid.cid_num : "<unknown>",
255 src->cid.cid_name ? src->cid.cid_name : "<unknown>", src->uniqueid,
259 static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localuser *outgoing, int *to, struct ast_flags *peerflags, int *sentringing, char *status, size_t statussize, int busystart, int nochanstart, int congestionstart, int *result)
264 int numbusy = busystart;
265 int numcongestion = congestionstart;
266 int numnochan = nochanstart;
267 int prestart = busystart + congestionstart + nochanstart;
271 struct ast_channel *peer = NULL;
272 struct ast_channel *watchers[AST_MAX_WATCHERS];
275 struct ast_channel *winner;
276 char *context = NULL;
277 char cidname[AST_MAX_EXTENSION];
279 single = (outgoing && !outgoing->next && !ast_test_flag(outgoing, DIAL_MUSICONHOLD | DIAL_RINGBACKONLY));
282 /* Turn off hold music, etc */
283 ast_deactivate_generator(in);
284 /* If we are calling a single channel, make them compatible for in-band tone purpose */
285 ast_channel_make_compatible(outgoing->chan, in);
289 while (*to && !peer) {
296 /* Keep track of important channels */
297 if (ast_test_flag(o, DIAL_STILLGOING) && o->chan) {
298 watchers[pos++] = o->chan;
305 if (numlines == (numbusy + numcongestion + numnochan)) {
306 if (option_verbose > 2)
307 ast_verbose( VERBOSE_PREFIX_2 "Everyone is busy/congested at this time (%d:%d/%d/%d)\n", numlines, numbusy, numcongestion, numnochan);
309 strncpy(status, "BUSY", statussize - 1);
310 else if (numcongestion)
311 strncpy(status, "CONGESTION", statussize - 1);
313 strncpy(status, "CHANUNAVAIL", statussize - 1);
314 /* See if there is a special busy message */
315 if (ast_exists_extension(in, in->context, in->exten, in->priority + 101, in->cid.cid_num))
318 if (option_verbose > 2)
319 ast_verbose( VERBOSE_PREFIX_2 "No one is available to answer at this time (%d:%d/%d/%d)\n", numlines, numbusy, numcongestion, numnochan);
324 winner = ast_waitfor_n(watchers, pos, to);
327 if (ast_test_flag(o, DIAL_STILLGOING) && o->chan && (o->chan->_state == AST_STATE_UP)) {
329 if (option_verbose > 2)
330 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
332 ast_copy_flags(peerflags, o, DIAL_ALLOWREDIRECT_IN|DIAL_ALLOWREDIRECT_OUT|DIAL_ALLOWDISCONNECT_IN|DIAL_ALLOWDISCONNECT_OUT|DIAL_NOFORWARDHTML);
334 } else if (o->chan && (o->chan == winner)) {
335 if (!ast_strlen_zero(o->chan->call_forward)) {
336 char tmpchan[256]="";
339 strncpy(tmpchan, o->chan->call_forward, sizeof(tmpchan) - 1);
340 if ((stuff = strchr(tmpchan, '/'))) {
345 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
349 /* Before processing channel, go ahead and check for forwarding */
351 if (o->forwards < AST_MAX_FORWARDS) {
352 if (option_verbose > 2)
353 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
354 /* Setup parameters */
355 o->chan = ast_request(tech, in->nativeformats, stuff, &cause);
357 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
359 if (option_verbose > 2)
360 ast_verbose(VERBOSE_PREFIX_3 "Too many forwards from %s\n", o->chan->name);
361 cause = AST_CAUSE_CONGESTION;
365 ast_clear_flag(o, DIAL_STILLGOING);
366 HANDLE_CAUSE(cause, in);
368 if (o->chan->cid.cid_num)
369 free(o->chan->cid.cid_num);
370 o->chan->cid.cid_num = NULL;
371 if (o->chan->cid.cid_name)
372 free(o->chan->cid.cid_name);
373 o->chan->cid.cid_name = NULL;
375 if (ast_test_flag(o, DIAL_FORCECALLERID)) {
378 if (strlen(in->macroexten))
379 newcid = in->macroexten;
382 o->chan->cid.cid_num = strdup(newcid);
383 strncpy(o->chan->accountcode, winner->accountcode, sizeof(o->chan->accountcode) - 1);
384 o->chan->cdrflags = winner->cdrflags;
385 if (!o->chan->cid.cid_num)
386 ast_log(LOG_WARNING, "Out of memory\n");
388 if (in->cid.cid_num) {
389 o->chan->cid.cid_num = strdup(in->cid.cid_num);
390 if (!o->chan->cid.cid_num)
391 ast_log(LOG_WARNING, "Out of memory\n");
393 if (in->cid.cid_name) {
394 o->chan->cid.cid_name = strdup(in->cid.cid_name);
395 if (!o->chan->cid.cid_name)
396 ast_log(LOG_WARNING, "Out of memory\n");
398 strncpy(o->chan->accountcode, in->accountcode, sizeof(o->chan->accountcode) - 1);
399 o->chan->cdrflags = in->cdrflags;
402 if (in->cid.cid_ani) {
403 if (o->chan->cid.cid_ani)
404 free(o->chan->cid.cid_ani);
405 o->chan->cid.cid_ani = malloc(strlen(in->cid.cid_ani) + 1);
406 if (o->chan->cid.cid_ani)
407 strncpy(o->chan->cid.cid_ani, in->cid.cid_ani, strlen(in->cid.cid_ani) + 1);
409 ast_log(LOG_WARNING, "Out of memory\n");
411 if (o->chan->cid.cid_rdnis)
412 free(o->chan->cid.cid_rdnis);
413 if (!ast_strlen_zero(in->macroexten))
414 o->chan->cid.cid_rdnis = strdup(in->macroexten);
416 o->chan->cid.cid_rdnis = strdup(in->exten);
417 if (ast_call(o->chan, tmpchan, 0)) {
418 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
419 ast_clear_flag(o, DIAL_STILLGOING);
424 senddialevent(in, o->chan);
425 /* After calling, set callerid to extension */
426 if (!ast_test_flag(peerflags, DIAL_PRESERVE_CALLERID))
427 ast_set_callerid(o->chan, ast_strlen_zero(in->macroexten) ? in->exten : in->macroexten, get_cid_name(cidname, sizeof(cidname), in), NULL);
430 /* Hangup the original channel now, in case we needed it */
434 f = ast_read(winner);
436 if (f->frametype == AST_FRAME_CONTROL) {
437 switch(f->subclass) {
438 case AST_CONTROL_ANSWER:
439 /* This is our guy if someone answered. */
441 if (option_verbose > 2)
442 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
444 ast_copy_flags(peerflags, o, DIAL_ALLOWREDIRECT_IN|DIAL_ALLOWREDIRECT_OUT|DIAL_ALLOWDISCONNECT_IN|DIAL_ALLOWDISCONNECT_OUT|DIAL_NOFORWARDHTML);
446 /* If call has been answered, then the eventual hangup is likely to be normal hangup */
447 in->hangupcause = AST_CAUSE_NORMAL_CLEARING;
448 o->chan->hangupcause = AST_CAUSE_NORMAL_CLEARING;
450 case AST_CONTROL_BUSY:
451 if (option_verbose > 2)
452 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
453 in->hangupcause = o->chan->hangupcause;
456 ast_clear_flag(o, DIAL_STILLGOING);
457 HANDLE_CAUSE(AST_CAUSE_BUSY, in);
459 case AST_CONTROL_CONGESTION:
460 if (option_verbose > 2)
461 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
462 in->hangupcause = o->chan->hangupcause;
465 ast_clear_flag(o, DIAL_STILLGOING);
466 HANDLE_CAUSE(AST_CAUSE_CONGESTION, in);
468 case AST_CONTROL_RINGING:
469 if (option_verbose > 2)
470 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
471 if (!(*sentringing) && !ast_test_flag(outgoing, DIAL_MUSICONHOLD)) {
472 ast_indicate(in, AST_CONTROL_RINGING);
476 case AST_CONTROL_PROGRESS:
477 if (option_verbose > 2)
478 ast_verbose ( VERBOSE_PREFIX_3 "%s is making progress passing it to %s\n", o->chan->name,in->name);
479 if (!ast_test_flag(outgoing, DIAL_RINGBACKONLY))
480 ast_indicate(in, AST_CONTROL_PROGRESS);
482 case AST_CONTROL_HOLD:
483 if (option_verbose > 2)
484 ast_verbose(VERBOSE_PREFIX_3 "Call on %s placed on hold\n", o->chan->name);
485 ast_indicate(in, AST_CONTROL_HOLD);
487 case AST_CONTROL_UNHOLD:
488 if (option_verbose > 2)
489 ast_verbose(VERBOSE_PREFIX_3 "Call on %s left from hold\n", o->chan->name);
490 ast_indicate(in, AST_CONTROL_UNHOLD);
492 case AST_CONTROL_OFFHOOK:
493 case AST_CONTROL_FLASH:
494 /* Ignore going off hook and flash */
497 if (!ast_test_flag(outgoing, DIAL_RINGBACKONLY | DIAL_MUSICONHOLD)) {
498 if (option_verbose > 2)
499 ast_verbose( VERBOSE_PREFIX_3 "%s stopped sounds\n", o->chan->name);
500 ast_indicate(in, -1);
505 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
507 } else if (single && (f->frametype == AST_FRAME_VOICE) &&
508 !(ast_test_flag(outgoing, DIAL_RINGBACKONLY|DIAL_MUSICONHOLD))) {
509 if (ast_write(in, f))
510 ast_log(LOG_WARNING, "Unable to forward frame\n");
511 } else if (single && (f->frametype == AST_FRAME_IMAGE) &&
512 !(ast_test_flag(outgoing, DIAL_RINGBACKONLY|DIAL_MUSICONHOLD))) {
513 if (ast_write(in, f))
514 ast_log(LOG_WARNING, "Unable to forward image\n");
515 } else if (single && (f->frametype == AST_FRAME_HTML) && !ast_test_flag(outgoing, DIAL_NOFORWARDHTML))
516 ast_channel_sendhtml(in, f->subclass, f->data, f->datalen);
520 in->hangupcause = o->chan->hangupcause;
523 ast_clear_flag(o, DIAL_STILLGOING);
531 if (f && (f->frametype != AST_FRAME_VOICE))
532 printf("Frame type: %d, %d\n", f->frametype, f->subclass);
533 else if (!f || (f->frametype != AST_FRAME_VOICE))
534 printf("Hangup received on %s\n", in->name);
536 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
539 strncpy(status, "CANCEL", statussize - 1);
545 if (f && (f->frametype == AST_FRAME_DTMF)) {
546 if (ast_test_flag(peerflags, DIAL_HALT_ON_DTMF)) {
547 context = pbx_builtin_getvar_helper(in, "EXITCONTEXT");
548 if (ast_onedigit_goto(in, context, (char) f->subclass, 1, in->cid.cid_num)) {
549 if (option_verbose > 3)
550 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
552 *result = f->subclass;
553 strcpy(status, "CANCEL");
559 if (ast_test_flag(peerflags, DIAL_ALLOWDISCONNECT_OUT) &&
560 (f->subclass == '*')) { /* hmm it it not guarenteed to be '*' anymore. */
561 if (option_verbose > 3)
562 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
564 strcpy(status, "CANCEL");
570 /* Forward HTML stuff */
571 if (single && f && (f->frametype == AST_FRAME_HTML) && !ast_test_flag(outgoing, DIAL_NOFORWARDHTML))
572 ast_channel_sendhtml(outgoing->chan, f->subclass, f->data, f->datalen);
575 if (single && ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_DTMF))) {
576 if (ast_write(outgoing->chan, f))
577 ast_log(LOG_WARNING, "Unable to forward voice\n");
581 if (!*to && (option_verbose > 2))
582 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
590 static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags *peerflags)
594 char *info, *peers, *timeout, *tech, *number, *rest, *cur;
595 char privdb[256] = "", *s;
596 char announcemsg[256] = "", *ann;
597 struct localuser *outgoing=NULL, *tmp;
598 struct ast_channel *peer;
605 int numcongestion = 0;
608 char numsubst[AST_MAX_EXTENSION];
609 char restofit[AST_MAX_EXTENSION];
610 char cidname[AST_MAX_EXTENSION];
611 char *transfer = NULL;
614 char *url=NULL; /* JDG */
615 unsigned int calldurationlimit=0;
618 struct ast_bridge_config config;
620 long play_warning = 0;
622 char *warning_sound=NULL;
623 char *end_sound=NULL;
624 char *start_sound=NULL;
628 char sdtmfdata[256] = "";
630 char *mac = NULL, *macroname = NULL;
633 int play_to_caller=0,play_to_callee=0;
634 int playargs=0, sentringing=0, moh=0;
635 char *mohclass = NULL;
636 char *outbound_group = NULL;
637 char *macro_result = NULL, *macro_transfer_dest = NULL;
638 int digit = 0, result = 0;
639 time_t start_time, answer_time, end_time;
640 struct ast_app *app = NULL;
643 ast_log(LOG_WARNING, "Dial requires an argument (technology1/number1&technology2/number2...|optional timeout|options)\n");
647 if (!(info = ast_strdupa(data))) {
648 ast_log(LOG_WARNING, "Unable to dupe data :(\n");
656 timeout = strchr(info, '|');
660 transfer = strchr(timeout, '|');
665 url = strchr(transfer, '|');
670 ast_log(LOG_DEBUG, "DIAL WITH URL=%s_\n", url);
673 ast_log(LOG_DEBUG, "SIMPLE DIAL (NO URL)\n");
680 if (!peers || ast_strlen_zero(peers)) {
681 ast_log(LOG_WARNING, "Dial argument takes format (technology1/number1&technology2/number2...|optional timeout)\n");
688 /* Extract call duration limit */
689 if ((cdl = strstr(transfer, "S("))) {
690 calldurationlimit=atoi(cdl+2);
691 if (option_verbose > 2)
692 ast_verbose(VERBOSE_PREFIX_3 "Setting call duration limit to %i seconds.\n",calldurationlimit);
696 if ((sdtmfptr = strstr(transfer, "D("))) {
697 strncpy(sdtmfdata, sdtmfptr + 2, sizeof(sdtmfdata) - 1);
698 /* Overwrite with X's what was the sdtmf info */
699 while (*sdtmfptr && (*sdtmfptr != ')'))
703 /* Now find the end */
704 sdtmfptr = strchr(sdtmfdata, ')');
708 ast_log(LOG_WARNING, "D( Data lacking trailing ')'\n");
711 /* XXX LIMIT SUPPORT */
712 if ((limitptr = strstr(transfer, "L("))) {
713 strncpy(limitdata, limitptr + 2, sizeof(limitdata) - 1);
714 /* Overwrite with X's what was the limit info */
715 while (*limitptr && (*limitptr != ')'))
719 /* Now find the end */
720 limitptr = strchr(limitdata, ')');
724 ast_log(LOG_WARNING, "Limit Data lacking trailing ')'\n");
726 var = pbx_builtin_getvar_helper(chan,"LIMIT_PLAYAUDIO_CALLER");
727 play_to_caller = var ? ast_true(var) : 1;
729 var = pbx_builtin_getvar_helper(chan,"LIMIT_PLAYAUDIO_CALLEE");
730 play_to_callee = var ? ast_true(var) : 0;
732 if (!play_to_caller && !play_to_callee)
735 var = pbx_builtin_getvar_helper(chan,"LIMIT_WARNING_FILE");
736 warning_sound = var ? var : "timeleft";
738 var = pbx_builtin_getvar_helper(chan,"LIMIT_TIMEOUT_FILE");
739 end_sound = var ? var : NULL;
741 var = pbx_builtin_getvar_helper(chan,"LIMIT_CONNECT_FILE");
742 start_sound = var ? var : NULL;
746 var = strsep(&stack, ":");
748 timelimit = atol(var);
750 var = strsep(&stack, ":");
752 play_warning = atol(var);
754 var = strsep(&stack, ":");
756 warning_freq = atol(var);
763 timelimit=play_to_caller=play_to_callee=play_warning=warning_freq=0;
766 /* undo effect of S(x) in case they are both used */
768 /* more efficient do it like S(x) does since no advanced opts*/
769 if (!play_warning && !start_sound && !end_sound && timelimit) {
770 calldurationlimit=timelimit/1000;
771 timelimit=play_to_caller=play_to_callee=play_warning=warning_freq=0;
772 } else if (option_verbose > 2) {
773 ast_verbose(VERBOSE_PREFIX_3"Limit Data:\n");
774 ast_verbose(VERBOSE_PREFIX_3"timelimit=%ld\n",timelimit);
775 ast_verbose(VERBOSE_PREFIX_3"play_warning=%ld\n",play_warning);
776 ast_verbose(VERBOSE_PREFIX_3"play_to_caller=%s\n",play_to_caller ? "yes" : "no");
777 ast_verbose(VERBOSE_PREFIX_3"play_to_callee=%s\n",play_to_callee ? "yes" : "no");
778 ast_verbose(VERBOSE_PREFIX_3"warning_freq=%ld\n",warning_freq);
779 ast_verbose(VERBOSE_PREFIX_3"start_sound=%s\n",start_sound ? start_sound : "UNDEF");
780 ast_verbose(VERBOSE_PREFIX_3"warning_sound=%s\n",warning_sound ? warning_sound : "UNDEF");
781 ast_verbose(VERBOSE_PREFIX_3"end_sound=%s\n",end_sound ? end_sound : "UNDEF");
785 /* XXX ANNOUNCE SUPPORT */
786 if ((ann = strstr(transfer, "A("))) {
788 strncpy(announcemsg, ann + 2, sizeof(announcemsg) - 1);
789 /* Overwrite with X's what was the announce info */
790 while (*ann && (*ann != ')'))
794 /* Now find the end of the privdb */
795 ann = strchr(announcemsg, ')');
799 ast_log(LOG_WARNING, "Transfer with Announce spec lacking trailing ')'\n");
804 /* Get the macroname from the dial option string */
805 if ((mac = strstr(transfer, "M("))) {
807 macroname = ast_strdupa(mac + 2);
808 while (*mac && (*mac != ')'))
813 ast_log(LOG_WARNING, "Could not find macro to which we should jump.\n");
816 mac = strchr(macroname, ')');
820 ast_log(LOG_WARNING, "Macro flag set without trailing ')'\n");
824 /* Get music on hold class */
825 if ((mac = strstr(transfer, "m("))) {
826 mohclass = ast_strdupa(mac + 2);
827 mac++; /* Leave the "m" in the string */
828 while (*mac && (*mac != ')'))
832 mac = strchr(mohclass, ')');
836 ast_log(LOG_WARNING, "Music on hold class specified without trailing ')'\n");
840 ast_log(LOG_WARNING, "Could not find music on hold class to use, assuming default.\n");
844 /* Extract privacy info from transfer */
845 if ((s = strstr(transfer, "P("))) {
847 strncpy(privdb, s + 2, sizeof(privdb) - 1);
848 /* Overwrite with X's what was the privacy info */
849 while (*s && (*s != ')'))
853 /* Now find the end of the privdb */
854 s = strchr(privdb, ')');
858 ast_log(LOG_WARNING, "Transfer with privacy lacking trailing ')'\n");
861 } else if (strchr(transfer, 'P')) {
862 /* No specified privdb */
864 } else if (strchr(transfer, 'C')) {
868 if (resetcdr && chan->cdr)
869 ast_cdr_reset(chan->cdr, 0);
870 if (ast_strlen_zero(privdb) && privacy) {
871 /* If privdb is not specified and we are using privacy, copy from extension */
872 strncpy(privdb, chan->exten, sizeof(privdb) - 1);
875 l = chan->cid.cid_num;
878 ast_log(LOG_NOTICE, "Privacy DB is '%s', privacy is %d, clid is '%s'\n", privdb, privacy, l);
881 /* If a channel group has been specified, get it for use when we create peer channels */
882 outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP");
886 /* Remember where to start next time */
887 rest = strchr(cur, '&');
892 /* Get a technology/[device:]number pair */
894 number = strchr(tech, '/');
896 ast_log(LOG_WARNING, "Dial argument takes format (technology1/[device:]number1&technology2/[device:]number2...|optional timeout)\n");
901 tmp = malloc(sizeof(struct localuser));
903 ast_log(LOG_WARNING, "Out of memory\n");
906 memset(tmp, 0, sizeof(struct localuser));
908 ast_set2_flag(tmp, strchr(transfer, 't'), DIAL_ALLOWREDIRECT_IN);
909 ast_set2_flag(tmp, strchr(transfer, 'T'), DIAL_ALLOWREDIRECT_OUT);
910 ast_set2_flag(tmp, strchr(transfer, 'r'), DIAL_RINGBACKONLY);
911 ast_set2_flag(tmp, strchr(transfer, 'm'), DIAL_MUSICONHOLD);
912 ast_set2_flag(tmp, strchr(transfer, 'H'), DIAL_ALLOWDISCONNECT_OUT);
913 ast_set2_flag(peerflags, strchr(transfer, 'H'), DIAL_ALLOWDISCONNECT_OUT);
914 ast_set2_flag(tmp, strchr(transfer, 'h'), DIAL_ALLOWDISCONNECT_IN);
915 ast_set2_flag(peerflags, strchr(transfer, 'h'), DIAL_ALLOWDISCONNECT_IN);
916 ast_set2_flag(tmp, strchr(transfer, 'f'), DIAL_FORCECALLERID);
917 ast_set2_flag(tmp, url, DIAL_NOFORWARDHTML);
918 ast_set2_flag(peerflags, strchr(transfer, 'w'), DIAL_MONITOR_IN);
919 ast_set2_flag(peerflags, strchr(transfer, 'W'), DIAL_MONITOR_OUT);
920 ast_set2_flag(peerflags, strchr(transfer, 'd'), DIAL_HALT_ON_DTMF);
921 ast_set2_flag(peerflags, strchr(transfer, 'g'), DIAL_GO_ON);
922 ast_set2_flag(peerflags, strchr(transfer, 'o'), DIAL_PRESERVE_CALLERID);
924 strncpy(numsubst, number, sizeof(numsubst)-1);
925 /* If we're dialing by extension, look at the extension to know what to dial */
926 if ((newnum = strstr(numsubst, "BYEXTENSION"))) {
927 strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit)-1);
928 snprintf(newnum, sizeof(numsubst) - (newnum - numsubst), "%s%s", chan->exten,restofit);
930 ast_log(LOG_DEBUG, "Dialing by extension %s\n", numsubst);
932 /* Request the peer */
933 tmp->chan = ast_request(tech, chan->nativeformats, numsubst, &cause);
935 /* If we can't, just go on to the next call */
936 ast_log(LOG_NOTICE, "Unable to create channel of type '%s' (cause %d)\n", tech, cause);
937 HANDLE_CAUSE(cause, chan);
941 pbx_builtin_setvar_helper(tmp->chan, "DIALEDPEERNUMBER", numsubst);
942 if (!ast_strlen_zero(tmp->chan->call_forward)) {
943 char tmpchan[256]="";
946 strncpy(tmpchan, tmp->chan->call_forward, sizeof(tmpchan) - 1);
947 if ((stuff = strchr(tmpchan, '/'))) {
952 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", tmp->chan->call_forward, tmp->chan->context);
957 if (tmp->forwards < AST_MAX_FORWARDS) {
958 if (option_verbose > 2)
959 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", chan->name, tech, stuff, tmp->chan->name);
960 ast_hangup(tmp->chan);
961 /* Setup parameters */
962 tmp->chan = ast_request(tech, chan->nativeformats, stuff, &cause);
964 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
966 if (option_verbose > 2)
967 ast_verbose(VERBOSE_PREFIX_3 "Too many forwards from %s\n", tmp->chan->name);
968 ast_hangup(tmp->chan);
970 cause = AST_CAUSE_CONGESTION;
973 HANDLE_CAUSE(cause, chan);
979 /* Inherit specially named variables from parent channel */
980 ast_channel_inherit_variables(chan, tmp->chan);
982 tmp->chan->appl = "AppDial";
983 tmp->chan->data = "(Outgoing Line)";
984 tmp->chan->whentohangup = 0;
985 if (tmp->chan->cid.cid_num)
986 free(tmp->chan->cid.cid_num);
987 tmp->chan->cid.cid_num = NULL;
988 if (tmp->chan->cid.cid_name)
989 free(tmp->chan->cid.cid_name);
990 tmp->chan->cid.cid_name = NULL;
991 if (tmp->chan->cid.cid_ani)
992 free(tmp->chan->cid.cid_ani);
993 tmp->chan->cid.cid_ani = NULL;
995 if (chan->cid.cid_num)
996 tmp->chan->cid.cid_num = strdup(chan->cid.cid_num);
997 if (chan->cid.cid_name)
998 tmp->chan->cid.cid_name = strdup(chan->cid.cid_name);
999 if (chan->cid.cid_ani)
1000 tmp->chan->cid.cid_ani = strdup(chan->cid.cid_ani);
1002 /* Copy language from incoming to outgoing */
1003 strncpy(tmp->chan->language, chan->language, sizeof(tmp->chan->language) - 1);
1004 strncpy(tmp->chan->accountcode, chan->accountcode, sizeof(tmp->chan->accountcode) - 1);
1005 tmp->chan->cdrflags = chan->cdrflags;
1006 if (ast_strlen_zero(tmp->chan->musicclass))
1007 strncpy(tmp->chan->musicclass, chan->musicclass, sizeof(tmp->chan->musicclass) - 1);
1008 if (chan->cid.cid_rdnis)
1009 tmp->chan->cid.cid_rdnis = strdup(chan->cid.cid_rdnis);
1010 /* Pass callingpres setting */
1011 tmp->chan->cid.cid_pres = chan->cid.cid_pres;
1012 /* Pass type of number */
1013 tmp->chan->cid.cid_ton = chan->cid.cid_ton;
1014 /* Pass type of tns */
1015 tmp->chan->cid.cid_tns = chan->cid.cid_tns;
1016 /* Presense of ADSI CPE on outgoing channel follows ours */
1017 tmp->chan->adsicpe = chan->adsicpe;
1018 /* pass the digital flag */
1019 ast_copy_flags(tmp->chan, chan, AST_FLAG_DIGITAL);
1021 /* If we have an outbound group, set this peer channel to it */
1023 ast_app_group_set_channel(tmp->chan, outbound_group);
1025 /* Place the call, but don't wait on the answer */
1026 res = ast_call(tmp->chan, numsubst, 0);
1028 /* Save the info in cdr's that we called them */
1030 ast_cdr_setdestchan(chan->cdr, tmp->chan->name);
1032 /* check the results of ast_call */
1034 /* Again, keep going even if there's an error */
1036 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
1037 else if (option_verbose > 2)
1038 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", numsubst);
1039 ast_hangup(tmp->chan);
1044 senddialevent(chan, tmp->chan);
1045 if (option_verbose > 2)
1046 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", numsubst);
1047 if (!ast_test_flag(peerflags, DIAL_PRESERVE_CALLERID))
1048 ast_set_callerid(tmp->chan, ast_strlen_zero(chan->macroexten) ? chan->exten : chan->macroexten, get_cid_name(cidname, sizeof(cidname), chan), NULL);
1050 /* Put them in the list of outgoing thingies... We're ready now.
1051 XXX If we're forcibly removed, these outgoing calls won't get
1053 ast_set_flag(tmp, DIAL_STILLGOING);
1054 tmp->next = outgoing;
1056 /* If this line is up, don't try anybody else */
1057 if (outgoing->chan->_state == AST_STATE_UP)
1062 if (timeout && !ast_strlen_zero(timeout)) {
1067 ast_log(LOG_WARNING, "Invalid timeout specified: '%s'\n", timeout);
1072 /* Our status will at least be NOANSWER */
1073 strncpy(status, "NOANSWER", sizeof(status) - 1);
1074 if (ast_test_flag(outgoing, DIAL_MUSICONHOLD)) {
1076 ast_moh_start(chan, mohclass);
1077 } else if (ast_test_flag(outgoing, DIAL_RINGBACKONLY)) {
1078 ast_indicate(chan, AST_CONTROL_RINGING);
1082 strncpy(status, "CHANUNAVAIL", sizeof(status) - 1);
1085 peer = wait_for_answer(chan, outgoing, &to, peerflags, &sentringing, status, sizeof(status), numbusy, numnochan, numcongestion, &result);
1092 /* Musta gotten hung up */
1095 /* Nobody answered, next please? */
1103 /* Once call is answered, ditch the OSP Handle */
1104 pbx_builtin_setvar_helper(chan, "_OSPHANDLE", "");
1106 strncpy(status, "ANSWER", sizeof(status) - 1);
1107 /* Ah ha! Someone answered within the desired timeframe. Of course after this
1108 we will always return with -1 so that it is hung up properly after the
1110 hanguptree(outgoing, peer);
1112 /* If appropriate, log that we have a destination channel */
1114 ast_cdr_setdestchan(chan->cdr, peer->name);
1116 pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", peer->name);
1118 number = pbx_builtin_getvar_helper(peer, "DIALEDPEERNUMBER");
1121 pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", number);
1123 if ( url && !ast_strlen_zero(url) && ast_channel_supports_html(peer) ) {
1124 ast_log(LOG_DEBUG, "app_dial: sendurl=%s.\n", url);
1125 ast_channel_sendurl( peer, url );
1127 if (announce && announcemsg) {
1128 /* Start autoservice on the other chan */
1129 res = ast_autoservice_start(chan);
1130 /* Now Stream the File */
1132 res = ast_streamfile(peer,announcemsg,peer->language);
1134 digit = ast_waitstream(peer, AST_DIGIT_ANY);
1136 /* Ok, done. stop autoservice */
1137 res = ast_autoservice_stop(chan);
1138 if (digit > 0 && !res)
1139 res = ast_senddigit(chan, digit);
1146 if (hasmacro && macroname) {
1147 res = ast_autoservice_start(chan);
1149 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
1153 app = pbx_findapp("Macro");
1156 for (res=0;res<strlen(macroname);res++)
1157 if (macroname[res] == '^')
1158 macroname[res] = '|';
1159 res = pbx_exec(peer, app, macroname, 1);
1160 ast_log(LOG_DEBUG, "Macro exited with status %d\n", res);
1163 ast_log(LOG_ERROR, "Could not find application Macro\n");
1167 if (ast_autoservice_stop(chan) < 0) {
1168 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
1173 if ((macro_result = pbx_builtin_getvar_helper(peer, "MACRO_RESULT"))) {
1174 if (!strcasecmp(macro_result, "BUSY")) {
1175 strncpy(status, macro_result, sizeof(status) - 1);
1176 if (!ast_goto_if_exists(chan, NULL, NULL, chan->priority + 101)) {
1177 ast_set_flag(peerflags, DIAL_GO_ON);
1181 else if (!strcasecmp(macro_result, "CONGESTION") || !strcasecmp(macro_result, "CHANUNAVAIL")) {
1182 strncpy(status, macro_result, sizeof(status) - 1);
1183 ast_set_flag(peerflags, DIAL_GO_ON);
1186 else if (!strcasecmp(macro_result, "CONTINUE")) {
1187 /* hangup peer and keep chan alive assuming the macro has changed
1188 the context / exten / priority or perhaps
1189 the next priority in the current exten is desired.
1191 ast_set_flag(peerflags, DIAL_GO_ON);
1193 } else if (!strcasecmp(macro_result, "ABORT")) {
1194 /* Hangup both ends unless the caller has the g flag */
1196 } else if (!strncasecmp(macro_result, "GOTO:",5) && (macro_transfer_dest = ast_strdupa(macro_result + 5))) {
1198 /* perform a transfer to a new extension */
1199 if (strchr(macro_transfer_dest,'^')) { /* context^exten^priority*/
1200 /* no brainer mode... substitute ^ with | and feed it to builtin goto */
1201 for (res=0;res<strlen(macro_transfer_dest);res++)
1202 if (macro_transfer_dest[res] == '^')
1203 macro_transfer_dest[res] = '|';
1205 if (!ast_parseable_goto(chan, macro_transfer_dest))
1206 ast_set_flag(peerflags, DIAL_GO_ON);
1215 if (calldurationlimit > 0) {
1217 chan->whentohangup = now + calldurationlimit;
1219 if (!ast_strlen_zero(sdtmfdata))
1220 res = ast_dtmf_stream(peer,chan,sdtmfdata,250);
1224 memset(&config,0,sizeof(struct ast_bridge_config));
1226 ast_set_flag(&(config.features_caller), AST_FEATURE_PLAY_WARNING);
1228 ast_set_flag(&(config.features_callee), AST_FEATURE_PLAY_WARNING);
1229 if (ast_test_flag(peerflags, DIAL_ALLOWREDIRECT_IN))
1230 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
1231 if (ast_test_flag(peerflags, DIAL_ALLOWREDIRECT_OUT))
1232 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
1233 if (ast_test_flag(peerflags, DIAL_ALLOWDISCONNECT_IN))
1234 ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
1235 if (ast_test_flag(peerflags, DIAL_ALLOWDISCONNECT_OUT))
1236 ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
1237 if (ast_test_flag(peerflags, DIAL_MONITOR_IN))
1238 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
1239 if (ast_test_flag(peerflags, DIAL_MONITOR_OUT))
1240 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
1242 config.timelimit = timelimit;
1243 config.play_warning = play_warning;
1244 config.warning_freq = warning_freq;
1245 config.warning_sound = warning_sound;
1246 config.end_sound = end_sound;
1247 config.start_sound = start_sound;
1251 } else if (sentringing) {
1253 ast_indicate(chan, -1);
1255 /* Be sure no generators are left on it */
1256 ast_deactivate_generator(chan);
1257 /* Make sure channels are compatible */
1258 res = ast_channel_make_compatible(chan, peer);
1260 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", chan->name, peer->name);
1264 res = ast_bridge_call(chan,peer,&config);
1266 snprintf(toast, sizeof(toast), "%ld", (long)(end_time - start_time));
1267 pbx_builtin_setvar_helper(chan, "DIALEDTIME", toast);
1268 snprintf(toast, sizeof(toast), "%ld", (long)(end_time - answer_time));
1269 pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", toast);
1274 if (res != AST_PBX_NO_HANGUP_PEER) {
1275 if (!chan->_softhangup)
1276 chan->hangupcause = peer->hangupcause;
1284 } else if (sentringing) {
1286 ast_indicate(chan, -1);
1288 hanguptree(outgoing, NULL);
1289 pbx_builtin_setvar_helper(chan, "DIALSTATUS", status);
1290 ast_log(LOG_DEBUG, "Exiting with DIALSTATUS=%s.\n", status);
1292 LOCAL_USER_REMOVE(u);
1294 if ((ast_test_flag(peerflags, DIAL_GO_ON)) && (!chan->_softhangup) && (res != AST_PBX_KEEPALIVE))
1300 static int dial_exec(struct ast_channel *chan, void *data)
1302 struct ast_flags peerflags;
1303 memset(&peerflags, 0, sizeof(peerflags));
1304 return dial_exec_full(chan, data, &peerflags);
1307 static int retrydial_exec(struct ast_channel *chan, void *data)
1309 char *announce = NULL, *context = NULL, *dialdata = NULL;
1310 int sleep = 0, loops = 0, res = 0;
1311 struct localuser *u = NULL;
1312 struct ast_flags peerflags;
1314 memset(&peerflags, 0, sizeof(peerflags));
1318 if (!data || !(announce = ast_strdupa(data))) {
1319 ast_log(LOG_ERROR, "Out of memory!\n");
1320 LOCAL_USER_REMOVE(u);
1324 if ((dialdata = strchr(announce, '|'))) {
1327 if ((sleep = atoi(dialdata))) {
1330 ast_log(LOG_ERROR, "%s requires the numerical argument <sleep>\n",rapp);
1331 LOCAL_USER_REMOVE(u);
1334 if ((dialdata = strchr(dialdata, '|'))) {
1337 if (!(loops = atoi(dialdata))) {
1338 ast_log(LOG_ERROR, "%s requires the numerical argument <loops>\n",rapp);
1339 LOCAL_USER_REMOVE(u);
1345 if ((dialdata = strchr(dialdata, '|'))) {
1349 ast_log(LOG_ERROR, "%s requires more arguments\n",rapp);
1350 LOCAL_USER_REMOVE(u);
1360 context = pbx_builtin_getvar_helper(chan, "EXITCONTEXT");
1363 chan->data = "Retrying";
1364 if (ast_test_flag(chan, AST_FLAG_MOH))
1367 if ((res = dial_exec_full(chan, dialdata, &peerflags)) == 0) {
1368 if (ast_test_flag(&peerflags, DIAL_HALT_ON_DTMF)) {
1369 if (!(res = ast_streamfile(chan, announce, chan->language)))
1370 res = ast_waitstream(chan, AST_DIGIT_ANY);
1371 if (!res && sleep) {
1372 if (!ast_test_flag(chan, AST_FLAG_MOH))
1373 ast_moh_start(chan, NULL);
1374 res = ast_waitfordigit(chan, sleep);
1377 if (!(res = ast_streamfile(chan, announce, chan->language)))
1378 res = ast_waitstream(chan, "");
1380 if (!ast_test_flag(chan, AST_FLAG_MOH))
1381 ast_moh_start(chan, NULL);
1383 res = ast_safe_sleep(chan, sleep);
1390 else if (res > 0) { /* Trying to send the call elsewhere (1 digit ext) */
1391 if (ast_onedigit_goto(chan, context, (char) res, 1, chan->cid.cid_num)) {
1399 if (ast_test_flag(chan, AST_FLAG_MOH))
1402 LOCAL_USER_REMOVE(u);
1403 return loops ? res : 0;
1407 int unload_module(void)
1409 STANDARD_HANGUP_LOCALUSERS;
1410 ast_unregister_application(app);
1411 return ast_unregister_application(rapp);
1414 int load_module(void)
1417 if (!(res = ast_register_application(app, dial_exec, synopsis, descrip)))
1418 res = ast_register_application(rapp, retrydial_exec, rsynopsis, rdescrip);
1422 char *description(void)
1430 STANDARD_USECOUNT(res);
1436 return ASTERISK_GPL_KEY;