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 " 'G(context^exten^pri)' -- If the call is answered transfer both parties to the specified exten.\n"
93 " 'A(x)' -- play an announcement to the called party, using x as file\n"
94 " 'S(x)' -- hangup the call after x seconds AFTER called party picked up\n"
95 " 'D([digits])' -- Send DTMF digit string *after* called party has answered\n"
96 " but before the bridge. (w=500ms sec pause)\n"
97 " 'L(x[:y][:z])' -- Limit the call to 'x' ms warning when 'y' ms are left\n"
98 " repeated every 'z' ms) Only 'x' is required, 'y' and 'z' are optional.\n"
99 " The following special variables are optional:\n"
100 " * LIMIT_PLAYAUDIO_CALLER yes|no (default yes)\n"
101 " Play sounds to the caller.\n"
102 " * LIMIT_PLAYAUDIO_CALLEE yes|no\n"
103 " Play sounds to the callee.\n"
104 " * LIMIT_TIMEOUT_FILE File to play when time is up.\n"
105 " * LIMIT_CONNECT_FILE File to play when call begins.\n"
106 " * LIMIT_WARNING_FILE File to play as warning if 'y' is defined.\n"
107 " 'timeleft' is a special sound macro to auto-say the time \n"
108 " left and is the default.\n\n"
109 " In addition to transferring the call, a call may be parked and then picked\n"
110 "up by another user.\n"
111 " The optional URL will be sent to the called party if the channel supports it.\n"
112 " If the OUTBOUND_GROUP variable is set, all peer channels created by this\n"
113 " application will be put into that group (as in SetGroup).\n"
114 " This application sets the following channel variables upon completion:\n"
115 " DIALEDTIME Time from dial to answer\n"
116 " ANSWEREDTIME Time for actual call\n"
117 " DIALSTATUS The status of the call as a text string, one of\n"
118 " CHANUNAVAIL | CONGESTION | NOANSWER | BUSY | ANSWER | CANCEL\n"
121 /* RetryDial App by Anthony Minessale II <anthmct@yahoo.com> Jan/2005 */
122 static char *rapp = "RetryDial";
123 static char *rsynopsis = "Place a call, retrying on failure allowing optional exit extension.\n";
124 static char *rdescrip =
125 " RetryDial(announce|sleep|loops|Technology/resource[&Technology2/resource2...][|timeout][|options][|URL]):\n"
126 "Attempt to place a call. If no channel can be reached, play the file defined by 'announce'\n"
127 "waiting 'sleep' seconds to retry the call. If the specified number of attempts matches \n"
128 "'loops' the call will continue in the dialplan. If 'loops' is set to 0, the call will retry endlessly.\n\n"
129 "While waiting, a 1 digit extension may be dialed. If that extension exists in either\n"
130 "the context defined in ${EXITCONTEXT} or the current one, The call will transfer\n"
131 "to that extension immmediately.\n\n"
132 "All arguments after 'loops' are passed directly to the Dial() application.\n"
136 /* We define a customer "local user" structure because we
137 use it not only for keeping track of what is in use but
138 also for keeping track of who we're dialing. */
140 #define DIAL_STILLGOING (1 << 0)
141 #define DIAL_ALLOWREDIRECT_IN (1 << 1)
142 #define DIAL_ALLOWREDIRECT_OUT (1 << 2)
143 #define DIAL_ALLOWDISCONNECT_IN (1 << 3)
144 #define DIAL_ALLOWDISCONNECT_OUT (1 << 4)
145 #define DIAL_RINGBACKONLY (1 << 5)
146 #define DIAL_MUSICONHOLD (1 << 6)
147 #define DIAL_FORCECALLERID (1 << 7)
148 #define DIAL_MONITOR_IN (1 << 8)
149 #define DIAL_MONITOR_OUT (1 << 9)
150 #define DIAL_GO_ON (1 << 10)
151 #define DIAL_HALT_ON_DTMF (1 << 11)
152 #define DIAL_PRESERVE_CALLERID (1 << 12)
153 #define DIAL_NOFORWARDHTML (1 << 13)
156 struct ast_channel *chan;
159 struct localuser *next;
164 static void hanguptree(struct localuser *outgoing, struct ast_channel *exception)
166 /* Hang up a tree of stuff */
167 struct localuser *oo;
169 /* Hangup any existing lines we have open */
170 if (outgoing->chan && (outgoing->chan != exception))
171 ast_hangup(outgoing->chan);
173 outgoing=outgoing->next;
178 #define AST_MAX_FORWARDS 8
180 #define AST_MAX_WATCHERS 256
182 #define HANDLE_CAUSE(cause, chan) do { \
184 case AST_CAUSE_BUSY: \
186 ast_cdr_busy(chan->cdr); \
189 case AST_CAUSE_CONGESTION: \
190 case AST_CAUSE_UNREGISTERED: \
192 ast_cdr_busy(chan->cdr); \
202 static int ast_onedigit_goto(struct ast_channel *chan, char *context, char exten, int pri, char *cid)
205 snprintf(rexten, 2, "%c", exten);
207 if (ast_exists_extension(chan, context, rexten, pri, cid)) {
208 ast_explicit_goto(chan, context, rexten, pri-1);
212 if (ast_exists_extension(chan, chan->context, rexten, pri, cid)) {
213 ast_explicit_goto(chan, chan->context, rexten, pri-1);
215 } else if (!ast_strlen_zero(chan->macrocontext)) {
216 if (ast_exists_extension(chan, chan->macrocontext, rexten, pri, cid)) {
217 ast_explicit_goto(chan, chan->macrocontext, rexten, pri-1);
226 static char *get_cid_name(char *name, int namelen, struct ast_channel *chan)
230 if (!ast_strlen_zero(chan->macrocontext))
231 context = chan->macrocontext;
233 context = chan->context;
235 if (!ast_strlen_zero(chan->macroexten))
236 exten = chan->macroexten;
240 if (ast_get_hint(NULL, 0, name, namelen, chan, context, exten))
246 static void senddialevent(struct ast_channel *src, struct ast_channel *dst)
248 manager_event(EVENT_FLAG_CALL, "Dial",
250 "Destination: %s\r\n"
252 "CallerIDName: %s\r\n"
253 "SrcUniqueID: %s\r\n"
254 "DestUniqueID: %s\r\n",
255 src->name, dst->name, src->cid.cid_num ? src->cid.cid_num : "<unknown>",
256 src->cid.cid_name ? src->cid.cid_name : "<unknown>", src->uniqueid,
260 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)
265 int numbusy = busystart;
266 int numcongestion = congestionstart;
267 int numnochan = nochanstart;
268 int prestart = busystart + congestionstart + nochanstart;
272 struct ast_channel *peer = NULL;
273 struct ast_channel *watchers[AST_MAX_WATCHERS];
276 struct ast_channel *winner;
277 char *context = NULL;
278 char cidname[AST_MAX_EXTENSION];
280 single = (outgoing && !outgoing->next && !ast_test_flag(outgoing, DIAL_MUSICONHOLD | DIAL_RINGBACKONLY));
283 /* Turn off hold music, etc */
284 ast_deactivate_generator(in);
285 /* If we are calling a single channel, make them compatible for in-band tone purpose */
286 ast_channel_make_compatible(outgoing->chan, in);
290 while (*to && !peer) {
297 /* Keep track of important channels */
298 if (ast_test_flag(o, DIAL_STILLGOING) && o->chan) {
299 watchers[pos++] = o->chan;
306 if (numlines == (numbusy + numcongestion + numnochan)) {
307 if (option_verbose > 2)
308 ast_verbose( VERBOSE_PREFIX_2 "Everyone is busy/congested at this time (%d:%d/%d/%d)\n", numlines, numbusy, numcongestion, numnochan);
310 strncpy(status, "BUSY", statussize - 1);
311 else if (numcongestion)
312 strncpy(status, "CONGESTION", statussize - 1);
314 strncpy(status, "CHANUNAVAIL", statussize - 1);
315 /* See if there is a special busy message */
316 if (ast_exists_extension(in, in->context, in->exten, in->priority + 101, in->cid.cid_num))
319 if (option_verbose > 2)
320 ast_verbose( VERBOSE_PREFIX_2 "No one is available to answer at this time (%d:%d/%d/%d)\n", numlines, numbusy, numcongestion, numnochan);
325 winner = ast_waitfor_n(watchers, pos, to);
328 if (ast_test_flag(o, DIAL_STILLGOING) && o->chan && (o->chan->_state == AST_STATE_UP)) {
330 if (option_verbose > 2)
331 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
333 ast_copy_flags(peerflags, o, DIAL_ALLOWREDIRECT_IN|DIAL_ALLOWREDIRECT_OUT|DIAL_ALLOWDISCONNECT_IN|DIAL_ALLOWDISCONNECT_OUT|DIAL_NOFORWARDHTML);
335 } else if (o->chan && (o->chan == winner)) {
336 if (!ast_strlen_zero(o->chan->call_forward)) {
337 char tmpchan[256]="";
340 strncpy(tmpchan, o->chan->call_forward, sizeof(tmpchan) - 1);
341 if ((stuff = strchr(tmpchan, '/'))) {
346 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
350 /* Before processing channel, go ahead and check for forwarding */
352 if (o->forwards < AST_MAX_FORWARDS) {
353 if (option_verbose > 2)
354 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
355 /* Setup parameters */
356 o->chan = ast_request(tech, in->nativeformats, stuff, &cause);
358 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
360 if (option_verbose > 2)
361 ast_verbose(VERBOSE_PREFIX_3 "Too many forwards from %s\n", o->chan->name);
362 cause = AST_CAUSE_CONGESTION;
366 ast_clear_flag(o, DIAL_STILLGOING);
367 HANDLE_CAUSE(cause, in);
369 if (o->chan->cid.cid_num)
370 free(o->chan->cid.cid_num);
371 o->chan->cid.cid_num = NULL;
372 if (o->chan->cid.cid_name)
373 free(o->chan->cid.cid_name);
374 o->chan->cid.cid_name = NULL;
376 if (ast_test_flag(o, DIAL_FORCECALLERID)) {
379 if (strlen(in->macroexten))
380 newcid = in->macroexten;
383 o->chan->cid.cid_num = strdup(newcid);
384 strncpy(o->chan->accountcode, winner->accountcode, sizeof(o->chan->accountcode) - 1);
385 o->chan->cdrflags = winner->cdrflags;
386 if (!o->chan->cid.cid_num)
387 ast_log(LOG_WARNING, "Out of memory\n");
389 if (in->cid.cid_num) {
390 o->chan->cid.cid_num = strdup(in->cid.cid_num);
391 if (!o->chan->cid.cid_num)
392 ast_log(LOG_WARNING, "Out of memory\n");
394 if (in->cid.cid_name) {
395 o->chan->cid.cid_name = strdup(in->cid.cid_name);
396 if (!o->chan->cid.cid_name)
397 ast_log(LOG_WARNING, "Out of memory\n");
399 strncpy(o->chan->accountcode, in->accountcode, sizeof(o->chan->accountcode) - 1);
400 o->chan->cdrflags = in->cdrflags;
403 if (in->cid.cid_ani) {
404 if (o->chan->cid.cid_ani)
405 free(o->chan->cid.cid_ani);
406 o->chan->cid.cid_ani = malloc(strlen(in->cid.cid_ani) + 1);
407 if (o->chan->cid.cid_ani)
408 strncpy(o->chan->cid.cid_ani, in->cid.cid_ani, strlen(in->cid.cid_ani) + 1);
410 ast_log(LOG_WARNING, "Out of memory\n");
412 if (o->chan->cid.cid_rdnis)
413 free(o->chan->cid.cid_rdnis);
414 if (!ast_strlen_zero(in->macroexten))
415 o->chan->cid.cid_rdnis = strdup(in->macroexten);
417 o->chan->cid.cid_rdnis = strdup(in->exten);
418 if (ast_call(o->chan, tmpchan, 0)) {
419 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
420 ast_clear_flag(o, DIAL_STILLGOING);
425 senddialevent(in, o->chan);
426 /* After calling, set callerid to extension */
427 if (!ast_test_flag(peerflags, DIAL_PRESERVE_CALLERID))
428 ast_set_callerid(o->chan, ast_strlen_zero(in->macroexten) ? in->exten : in->macroexten, get_cid_name(cidname, sizeof(cidname), in), NULL);
431 /* Hangup the original channel now, in case we needed it */
435 f = ast_read(winner);
437 if (f->frametype == AST_FRAME_CONTROL) {
438 switch(f->subclass) {
439 case AST_CONTROL_ANSWER:
440 /* This is our guy if someone answered. */
442 if (option_verbose > 2)
443 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
445 ast_copy_flags(peerflags, o, DIAL_ALLOWREDIRECT_IN|DIAL_ALLOWREDIRECT_OUT|DIAL_ALLOWDISCONNECT_IN|DIAL_ALLOWDISCONNECT_OUT|DIAL_NOFORWARDHTML);
447 /* If call has been answered, then the eventual hangup is likely to be normal hangup */
448 in->hangupcause = AST_CAUSE_NORMAL_CLEARING;
449 o->chan->hangupcause = AST_CAUSE_NORMAL_CLEARING;
451 case AST_CONTROL_BUSY:
452 if (option_verbose > 2)
453 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
454 in->hangupcause = o->chan->hangupcause;
457 ast_clear_flag(o, DIAL_STILLGOING);
458 HANDLE_CAUSE(AST_CAUSE_BUSY, in);
460 case AST_CONTROL_CONGESTION:
461 if (option_verbose > 2)
462 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
463 in->hangupcause = o->chan->hangupcause;
466 ast_clear_flag(o, DIAL_STILLGOING);
467 HANDLE_CAUSE(AST_CAUSE_CONGESTION, in);
469 case AST_CONTROL_RINGING:
470 if (option_verbose > 2)
471 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
472 if (!(*sentringing) && !ast_test_flag(outgoing, DIAL_MUSICONHOLD)) {
473 ast_indicate(in, AST_CONTROL_RINGING);
477 case AST_CONTROL_PROGRESS:
478 if (option_verbose > 2)
479 ast_verbose ( VERBOSE_PREFIX_3 "%s is making progress passing it to %s\n", o->chan->name,in->name);
480 if (!ast_test_flag(outgoing, DIAL_RINGBACKONLY))
481 ast_indicate(in, AST_CONTROL_PROGRESS);
483 case AST_CONTROL_HOLD:
484 if (option_verbose > 2)
485 ast_verbose(VERBOSE_PREFIX_3 "Call on %s placed on hold\n", o->chan->name);
486 ast_indicate(in, AST_CONTROL_HOLD);
488 case AST_CONTROL_UNHOLD:
489 if (option_verbose > 2)
490 ast_verbose(VERBOSE_PREFIX_3 "Call on %s left from hold\n", o->chan->name);
491 ast_indicate(in, AST_CONTROL_UNHOLD);
493 case AST_CONTROL_OFFHOOK:
494 case AST_CONTROL_FLASH:
495 /* Ignore going off hook and flash */
498 if (!ast_test_flag(outgoing, DIAL_RINGBACKONLY | DIAL_MUSICONHOLD)) {
499 if (option_verbose > 2)
500 ast_verbose( VERBOSE_PREFIX_3 "%s stopped sounds\n", o->chan->name);
501 ast_indicate(in, -1);
506 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
508 } else if (single && (f->frametype == AST_FRAME_VOICE) &&
509 !(ast_test_flag(outgoing, DIAL_RINGBACKONLY|DIAL_MUSICONHOLD))) {
510 if (ast_write(in, f))
511 ast_log(LOG_WARNING, "Unable to forward frame\n");
512 } else if (single && (f->frametype == AST_FRAME_IMAGE) &&
513 !(ast_test_flag(outgoing, DIAL_RINGBACKONLY|DIAL_MUSICONHOLD))) {
514 if (ast_write(in, f))
515 ast_log(LOG_WARNING, "Unable to forward image\n");
516 } else if (single && (f->frametype == AST_FRAME_HTML) && !ast_test_flag(outgoing, DIAL_NOFORWARDHTML))
517 ast_channel_sendhtml(in, f->subclass, f->data, f->datalen);
521 in->hangupcause = o->chan->hangupcause;
524 ast_clear_flag(o, DIAL_STILLGOING);
532 if (f && (f->frametype != AST_FRAME_VOICE))
533 printf("Frame type: %d, %d\n", f->frametype, f->subclass);
534 else if (!f || (f->frametype != AST_FRAME_VOICE))
535 printf("Hangup received on %s\n", in->name);
537 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
540 strncpy(status, "CANCEL", statussize - 1);
546 if (f && (f->frametype == AST_FRAME_DTMF)) {
547 if (ast_test_flag(peerflags, DIAL_HALT_ON_DTMF)) {
548 context = pbx_builtin_getvar_helper(in, "EXITCONTEXT");
549 if (ast_onedigit_goto(in, context, (char) f->subclass, 1, in->cid.cid_num)) {
550 if (option_verbose > 3)
551 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
553 *result = f->subclass;
554 strcpy(status, "CANCEL");
560 if (ast_test_flag(peerflags, DIAL_ALLOWDISCONNECT_OUT) &&
561 (f->subclass == '*')) { /* hmm it it not guarenteed to be '*' anymore. */
562 if (option_verbose > 3)
563 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
565 strcpy(status, "CANCEL");
571 /* Forward HTML stuff */
572 if (single && f && (f->frametype == AST_FRAME_HTML) && !ast_test_flag(outgoing, DIAL_NOFORWARDHTML))
573 ast_channel_sendhtml(outgoing->chan, f->subclass, f->data, f->datalen);
576 if (single && ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_DTMF))) {
577 if (ast_write(outgoing->chan, f))
578 ast_log(LOG_WARNING, "Unable to forward voice\n");
582 if (!*to && (option_verbose > 2))
583 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
591 static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags *peerflags)
595 char *info, *peers, *timeout, *tech, *number, *rest, *cur;
596 char privdb[256] = "", *s;
597 char announcemsg[256] = "", *ann;
598 struct localuser *outgoing=NULL, *tmp;
599 struct ast_channel *peer;
606 int numcongestion = 0;
609 char numsubst[AST_MAX_EXTENSION];
610 char restofit[AST_MAX_EXTENSION];
611 char cidname[AST_MAX_EXTENSION];
612 char *transfer = NULL;
615 char *url=NULL; /* JDG */
616 unsigned int calldurationlimit=0;
619 struct ast_bridge_config config;
621 long play_warning = 0;
623 char *warning_sound=NULL;
624 char *end_sound=NULL;
625 char *start_sound=NULL;
629 char sdtmfdata[256] = "";
631 char *mac = NULL, *macroname = NULL;
634 int play_to_caller=0,play_to_callee=0;
635 int playargs=0, sentringing=0, moh=0;
636 char *mohclass = NULL;
637 char *outbound_group = NULL;
638 char *macro_result = NULL, *macro_transfer_dest = NULL;
639 int digit = 0, result = 0;
640 time_t start_time, answer_time, end_time;
641 struct ast_app *app = NULL;
642 char *dblgoto = NULL;
645 ast_log(LOG_WARNING, "Dial requires an argument (technology1/number1&technology2/number2...|optional timeout|options)\n");
649 if (!(info = ast_strdupa(data))) {
650 ast_log(LOG_WARNING, "Unable to dupe data :(\n");
658 timeout = strchr(info, '|');
662 transfer = strchr(timeout, '|');
667 url = strchr(transfer, '|');
672 ast_log(LOG_DEBUG, "DIAL WITH URL=%s_\n", url);
675 ast_log(LOG_DEBUG, "SIMPLE DIAL (NO URL)\n");
682 if (!peers || ast_strlen_zero(peers)) {
683 ast_log(LOG_WARNING, "Dial argument takes format (technology1/number1&technology2/number2...|optional timeout)\n");
690 /* Extract call duration limit */
691 if ((cdl = strstr(transfer, "S("))) {
692 calldurationlimit=atoi(cdl+2);
693 if (option_verbose > 2)
694 ast_verbose(VERBOSE_PREFIX_3 "Setting call duration limit to %i seconds.\n",calldurationlimit);
698 if ((sdtmfptr = strstr(transfer, "D("))) {
699 strncpy(sdtmfdata, sdtmfptr + 2, sizeof(sdtmfdata) - 1);
700 /* Overwrite with X's what was the sdtmf info */
701 while (*sdtmfptr && (*sdtmfptr != ')'))
705 /* Now find the end */
706 sdtmfptr = strchr(sdtmfdata, ')');
710 ast_log(LOG_WARNING, "D( Data lacking trailing ')'\n");
713 /* XXX LIMIT SUPPORT */
714 if ((limitptr = strstr(transfer, "L("))) {
715 strncpy(limitdata, limitptr + 2, sizeof(limitdata) - 1);
716 /* Overwrite with X's what was the limit info */
717 while (*limitptr && (*limitptr != ')'))
721 /* Now find the end */
722 limitptr = strchr(limitdata, ')');
726 ast_log(LOG_WARNING, "Limit Data lacking trailing ')'\n");
728 var = pbx_builtin_getvar_helper(chan,"LIMIT_PLAYAUDIO_CALLER");
729 play_to_caller = var ? ast_true(var) : 1;
731 var = pbx_builtin_getvar_helper(chan,"LIMIT_PLAYAUDIO_CALLEE");
732 play_to_callee = var ? ast_true(var) : 0;
734 if (!play_to_caller && !play_to_callee)
737 var = pbx_builtin_getvar_helper(chan,"LIMIT_WARNING_FILE");
738 warning_sound = var ? var : "timeleft";
740 var = pbx_builtin_getvar_helper(chan,"LIMIT_TIMEOUT_FILE");
741 end_sound = var ? var : NULL;
743 var = pbx_builtin_getvar_helper(chan,"LIMIT_CONNECT_FILE");
744 start_sound = var ? var : NULL;
748 var = strsep(&stack, ":");
750 timelimit = atol(var);
752 var = strsep(&stack, ":");
754 play_warning = atol(var);
756 var = strsep(&stack, ":");
758 warning_freq = atol(var);
765 timelimit=play_to_caller=play_to_callee=play_warning=warning_freq=0;
768 /* undo effect of S(x) in case they are both used */
770 /* more efficient do it like S(x) does since no advanced opts*/
771 if (!play_warning && !start_sound && !end_sound && timelimit) {
772 calldurationlimit=timelimit/1000;
773 timelimit=play_to_caller=play_to_callee=play_warning=warning_freq=0;
774 } else if (option_verbose > 2) {
775 ast_verbose(VERBOSE_PREFIX_3"Limit Data:\n");
776 ast_verbose(VERBOSE_PREFIX_3"timelimit=%ld\n",timelimit);
777 ast_verbose(VERBOSE_PREFIX_3"play_warning=%ld\n",play_warning);
778 ast_verbose(VERBOSE_PREFIX_3"play_to_caller=%s\n",play_to_caller ? "yes" : "no");
779 ast_verbose(VERBOSE_PREFIX_3"play_to_callee=%s\n",play_to_callee ? "yes" : "no");
780 ast_verbose(VERBOSE_PREFIX_3"warning_freq=%ld\n",warning_freq);
781 ast_verbose(VERBOSE_PREFIX_3"start_sound=%s\n",start_sound ? start_sound : "UNDEF");
782 ast_verbose(VERBOSE_PREFIX_3"warning_sound=%s\n",warning_sound ? warning_sound : "UNDEF");
783 ast_verbose(VERBOSE_PREFIX_3"end_sound=%s\n",end_sound ? end_sound : "UNDEF");
787 /* XXX ANNOUNCE SUPPORT */
788 if ((ann = strstr(transfer, "A("))) {
790 strncpy(announcemsg, ann + 2, sizeof(announcemsg) - 1);
791 /* Overwrite with X's what was the announce info */
792 while (*ann && (*ann != ')'))
796 /* Now find the end of the privdb */
797 ann = strchr(announcemsg, ')');
801 ast_log(LOG_WARNING, "Transfer with Announce spec lacking trailing ')'\n");
806 /* Get the goto from the dial option string */
807 if ((mac = strstr(transfer, "G("))) {
810 dblgoto = ast_strdupa(mac + 2);
811 while (*mac && (*mac != ')'))
816 ast_log(LOG_WARNING, "Could not find exten to which we should jump.\n");
819 mac = strchr(dblgoto, ')');
823 ast_log(LOG_WARNING, "Goto flag set without trailing ')'\n");
828 /* Get the macroname from the dial option string */
829 if ((mac = strstr(transfer, "M("))) {
831 macroname = ast_strdupa(mac + 2);
832 while (*mac && (*mac != ')'))
837 ast_log(LOG_WARNING, "Could not find macro to which we should jump.\n");
840 mac = strchr(macroname, ')');
844 ast_log(LOG_WARNING, "Macro flag set without trailing ')'\n");
848 /* Get music on hold class */
849 if ((mac = strstr(transfer, "m("))) {
850 mohclass = ast_strdupa(mac + 2);
851 mac++; /* Leave the "m" in the string */
852 while (*mac && (*mac != ')'))
856 mac = strchr(mohclass, ')');
860 ast_log(LOG_WARNING, "Music on hold class specified without trailing ')'\n");
864 ast_log(LOG_WARNING, "Could not find music on hold class to use, assuming default.\n");
868 /* Extract privacy info from transfer */
869 if ((s = strstr(transfer, "P("))) {
871 strncpy(privdb, s + 2, sizeof(privdb) - 1);
872 /* Overwrite with X's what was the privacy info */
873 while (*s && (*s != ')'))
877 /* Now find the end of the privdb */
878 s = strchr(privdb, ')');
882 ast_log(LOG_WARNING, "Transfer with privacy lacking trailing ')'\n");
885 } else if (strchr(transfer, 'P')) {
886 /* No specified privdb */
888 } else if (strchr(transfer, 'C')) {
892 if (resetcdr && chan->cdr)
893 ast_cdr_reset(chan->cdr, 0);
894 if (ast_strlen_zero(privdb) && privacy) {
895 /* If privdb is not specified and we are using privacy, copy from extension */
896 strncpy(privdb, chan->exten, sizeof(privdb) - 1);
899 l = chan->cid.cid_num;
902 ast_log(LOG_NOTICE, "Privacy DB is '%s', privacy is %d, clid is '%s'\n", privdb, privacy, l);
905 /* If a channel group has been specified, get it for use when we create peer channels */
906 outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP");
910 /* Remember where to start next time */
911 rest = strchr(cur, '&');
916 /* Get a technology/[device:]number pair */
918 number = strchr(tech, '/');
920 ast_log(LOG_WARNING, "Dial argument takes format (technology1/[device:]number1&technology2/[device:]number2...|optional timeout)\n");
925 tmp = malloc(sizeof(struct localuser));
927 ast_log(LOG_WARNING, "Out of memory\n");
930 memset(tmp, 0, sizeof(struct localuser));
932 ast_set2_flag(tmp, strchr(transfer, 't'), DIAL_ALLOWREDIRECT_IN);
933 ast_set2_flag(tmp, strchr(transfer, 'T'), DIAL_ALLOWREDIRECT_OUT);
934 ast_set2_flag(tmp, strchr(transfer, 'r'), DIAL_RINGBACKONLY);
935 ast_set2_flag(tmp, strchr(transfer, 'm'), DIAL_MUSICONHOLD);
936 ast_set2_flag(tmp, strchr(transfer, 'H'), DIAL_ALLOWDISCONNECT_OUT);
937 ast_set2_flag(peerflags, strchr(transfer, 'H'), DIAL_ALLOWDISCONNECT_OUT);
938 ast_set2_flag(tmp, strchr(transfer, 'h'), DIAL_ALLOWDISCONNECT_IN);
939 ast_set2_flag(peerflags, strchr(transfer, 'h'), DIAL_ALLOWDISCONNECT_IN);
940 ast_set2_flag(tmp, strchr(transfer, 'f'), DIAL_FORCECALLERID);
941 ast_set2_flag(tmp, url, DIAL_NOFORWARDHTML);
942 ast_set2_flag(peerflags, strchr(transfer, 'w'), DIAL_MONITOR_IN);
943 ast_set2_flag(peerflags, strchr(transfer, 'W'), DIAL_MONITOR_OUT);
944 ast_set2_flag(peerflags, strchr(transfer, 'd'), DIAL_HALT_ON_DTMF);
945 ast_set2_flag(peerflags, strchr(transfer, 'g'), DIAL_GO_ON);
946 ast_set2_flag(peerflags, strchr(transfer, 'o'), DIAL_PRESERVE_CALLERID);
948 strncpy(numsubst, number, sizeof(numsubst)-1);
949 /* If we're dialing by extension, look at the extension to know what to dial */
950 if ((newnum = strstr(numsubst, "BYEXTENSION"))) {
951 strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit)-1);
952 snprintf(newnum, sizeof(numsubst) - (newnum - numsubst), "%s%s", chan->exten,restofit);
954 ast_log(LOG_DEBUG, "Dialing by extension %s\n", numsubst);
956 /* Request the peer */
957 tmp->chan = ast_request(tech, chan->nativeformats, numsubst, &cause);
959 /* If we can't, just go on to the next call */
960 ast_log(LOG_NOTICE, "Unable to create channel of type '%s' (cause %d)\n", tech, cause);
961 HANDLE_CAUSE(cause, chan);
965 pbx_builtin_setvar_helper(tmp->chan, "DIALEDPEERNUMBER", numsubst);
966 if (!ast_strlen_zero(tmp->chan->call_forward)) {
967 char tmpchan[256]="";
970 strncpy(tmpchan, tmp->chan->call_forward, sizeof(tmpchan) - 1);
971 if ((stuff = strchr(tmpchan, '/'))) {
976 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", tmp->chan->call_forward, tmp->chan->context);
981 if (tmp->forwards < AST_MAX_FORWARDS) {
982 if (option_verbose > 2)
983 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", chan->name, tech, stuff, tmp->chan->name);
984 ast_hangup(tmp->chan);
985 /* Setup parameters */
986 tmp->chan = ast_request(tech, chan->nativeformats, stuff, &cause);
988 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
990 if (option_verbose > 2)
991 ast_verbose(VERBOSE_PREFIX_3 "Too many forwards from %s\n", tmp->chan->name);
992 ast_hangup(tmp->chan);
994 cause = AST_CAUSE_CONGESTION;
997 HANDLE_CAUSE(cause, chan);
1003 /* Inherit specially named variables from parent channel */
1004 ast_channel_inherit_variables(chan, tmp->chan);
1006 tmp->chan->appl = "AppDial";
1007 tmp->chan->data = "(Outgoing Line)";
1008 tmp->chan->whentohangup = 0;
1009 if (tmp->chan->cid.cid_num)
1010 free(tmp->chan->cid.cid_num);
1011 tmp->chan->cid.cid_num = NULL;
1012 if (tmp->chan->cid.cid_name)
1013 free(tmp->chan->cid.cid_name);
1014 tmp->chan->cid.cid_name = NULL;
1015 if (tmp->chan->cid.cid_ani)
1016 free(tmp->chan->cid.cid_ani);
1017 tmp->chan->cid.cid_ani = NULL;
1019 if (chan->cid.cid_num)
1020 tmp->chan->cid.cid_num = strdup(chan->cid.cid_num);
1021 if (chan->cid.cid_name)
1022 tmp->chan->cid.cid_name = strdup(chan->cid.cid_name);
1023 if (chan->cid.cid_ani)
1024 tmp->chan->cid.cid_ani = strdup(chan->cid.cid_ani);
1026 /* Copy language from incoming to outgoing */
1027 strncpy(tmp->chan->language, chan->language, sizeof(tmp->chan->language) - 1);
1028 strncpy(tmp->chan->accountcode, chan->accountcode, sizeof(tmp->chan->accountcode) - 1);
1029 tmp->chan->cdrflags = chan->cdrflags;
1030 if (ast_strlen_zero(tmp->chan->musicclass))
1031 strncpy(tmp->chan->musicclass, chan->musicclass, sizeof(tmp->chan->musicclass) - 1);
1032 if (chan->cid.cid_rdnis)
1033 tmp->chan->cid.cid_rdnis = strdup(chan->cid.cid_rdnis);
1034 /* Pass callingpres setting */
1035 tmp->chan->cid.cid_pres = chan->cid.cid_pres;
1036 /* Pass type of number */
1037 tmp->chan->cid.cid_ton = chan->cid.cid_ton;
1038 /* Pass type of tns */
1039 tmp->chan->cid.cid_tns = chan->cid.cid_tns;
1040 /* Presense of ADSI CPE on outgoing channel follows ours */
1041 tmp->chan->adsicpe = chan->adsicpe;
1042 /* pass the digital flag */
1043 ast_copy_flags(tmp->chan, chan, AST_FLAG_DIGITAL);
1045 /* If we have an outbound group, set this peer channel to it */
1047 ast_app_group_set_channel(tmp->chan, outbound_group);
1049 /* Place the call, but don't wait on the answer */
1050 res = ast_call(tmp->chan, numsubst, 0);
1052 /* Save the info in cdr's that we called them */
1054 ast_cdr_setdestchan(chan->cdr, tmp->chan->name);
1056 /* check the results of ast_call */
1058 /* Again, keep going even if there's an error */
1060 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
1061 else if (option_verbose > 2)
1062 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", numsubst);
1063 ast_hangup(tmp->chan);
1068 senddialevent(chan, tmp->chan);
1069 if (option_verbose > 2)
1070 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", numsubst);
1071 if (!ast_test_flag(peerflags, DIAL_PRESERVE_CALLERID))
1072 ast_set_callerid(tmp->chan, ast_strlen_zero(chan->macroexten) ? chan->exten : chan->macroexten, get_cid_name(cidname, sizeof(cidname), chan), NULL);
1074 /* Put them in the list of outgoing thingies... We're ready now.
1075 XXX If we're forcibly removed, these outgoing calls won't get
1077 ast_set_flag(tmp, DIAL_STILLGOING);
1078 tmp->next = outgoing;
1080 /* If this line is up, don't try anybody else */
1081 if (outgoing->chan->_state == AST_STATE_UP)
1086 if (timeout && !ast_strlen_zero(timeout)) {
1091 ast_log(LOG_WARNING, "Invalid timeout specified: '%s'\n", timeout);
1096 /* Our status will at least be NOANSWER */
1097 strncpy(status, "NOANSWER", sizeof(status) - 1);
1098 if (ast_test_flag(outgoing, DIAL_MUSICONHOLD)) {
1100 ast_moh_start(chan, mohclass);
1101 } else if (ast_test_flag(outgoing, DIAL_RINGBACKONLY)) {
1102 ast_indicate(chan, AST_CONTROL_RINGING);
1106 strncpy(status, "CHANUNAVAIL", sizeof(status) - 1);
1109 peer = wait_for_answer(chan, outgoing, &to, peerflags, &sentringing, status, sizeof(status), numbusy, numnochan, numcongestion, &result);
1116 /* Musta gotten hung up */
1119 /* Nobody answered, next please? */
1127 /* Once call is answered, ditch the OSP Handle */
1128 pbx_builtin_setvar_helper(chan, "_OSPHANDLE", "");
1130 strncpy(status, "ANSWER", sizeof(status) - 1);
1131 /* Ah ha! Someone answered within the desired timeframe. Of course after this
1132 we will always return with -1 so that it is hung up properly after the
1134 hanguptree(outgoing, peer);
1136 /* If appropriate, log that we have a destination channel */
1138 ast_cdr_setdestchan(chan->cdr, peer->name);
1140 pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", peer->name);
1142 number = pbx_builtin_getvar_helper(peer, "DIALEDPEERNUMBER");
1145 pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", number);
1147 if ( url && !ast_strlen_zero(url) && ast_channel_supports_html(peer) ) {
1148 ast_log(LOG_DEBUG, "app_dial: sendurl=%s.\n", url);
1149 ast_channel_sendurl( peer, url );
1151 if (announce && announcemsg) {
1152 /* Start autoservice on the other chan */
1153 res = ast_autoservice_start(chan);
1154 /* Now Stream the File */
1156 res = ast_streamfile(peer,announcemsg,peer->language);
1158 digit = ast_waitstream(peer, AST_DIGIT_ANY);
1160 /* Ok, done. stop autoservice */
1161 res = ast_autoservice_stop(chan);
1162 if (digit > 0 && !res)
1163 res = ast_senddigit(chan, digit);
1170 if (chan && peer && dblgoto) {
1171 for (mac=dblgoto; *mac; mac++) {
1176 ast_parseable_goto(chan, dblgoto);
1177 ast_parseable_goto(peer, dblgoto);
1179 ast_pbx_start(peer);
1180 hanguptree(outgoing, NULL);
1181 LOCAL_USER_REMOVE(u);
1185 if (hasmacro && macroname) {
1186 res = ast_autoservice_start(chan);
1188 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
1192 app = pbx_findapp("Macro");
1195 for (res=0;res<strlen(macroname);res++)
1196 if (macroname[res] == '^')
1197 macroname[res] = '|';
1198 res = pbx_exec(peer, app, macroname, 1);
1199 ast_log(LOG_DEBUG, "Macro exited with status %d\n", res);
1202 ast_log(LOG_ERROR, "Could not find application Macro\n");
1206 if (ast_autoservice_stop(chan) < 0) {
1207 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
1212 if ((macro_result = pbx_builtin_getvar_helper(peer, "MACRO_RESULT"))) {
1213 if (!strcasecmp(macro_result, "BUSY")) {
1214 strncpy(status, macro_result, sizeof(status) - 1);
1215 if (!ast_goto_if_exists(chan, NULL, NULL, chan->priority + 101)) {
1216 ast_set_flag(peerflags, DIAL_GO_ON);
1220 else if (!strcasecmp(macro_result, "CONGESTION") || !strcasecmp(macro_result, "CHANUNAVAIL")) {
1221 strncpy(status, macro_result, sizeof(status) - 1);
1222 ast_set_flag(peerflags, DIAL_GO_ON);
1225 else if (!strcasecmp(macro_result, "CONTINUE")) {
1226 /* hangup peer and keep chan alive assuming the macro has changed
1227 the context / exten / priority or perhaps
1228 the next priority in the current exten is desired.
1230 ast_set_flag(peerflags, DIAL_GO_ON);
1232 } else if (!strcasecmp(macro_result, "ABORT")) {
1233 /* Hangup both ends unless the caller has the g flag */
1235 } else if (!strncasecmp(macro_result, "GOTO:",5) && (macro_transfer_dest = ast_strdupa(macro_result + 5))) {
1237 /* perform a transfer to a new extension */
1238 if (strchr(macro_transfer_dest,'^')) { /* context^exten^priority*/
1239 /* no brainer mode... substitute ^ with | and feed it to builtin goto */
1240 for (res=0;res<strlen(macro_transfer_dest);res++)
1241 if (macro_transfer_dest[res] == '^')
1242 macro_transfer_dest[res] = '|';
1244 if (!ast_parseable_goto(chan, macro_transfer_dest))
1245 ast_set_flag(peerflags, DIAL_GO_ON);
1254 if (calldurationlimit > 0) {
1256 chan->whentohangup = now + calldurationlimit;
1258 if (!ast_strlen_zero(sdtmfdata))
1259 res = ast_dtmf_stream(peer,chan,sdtmfdata,250);
1263 memset(&config,0,sizeof(struct ast_bridge_config));
1265 ast_set_flag(&(config.features_caller), AST_FEATURE_PLAY_WARNING);
1267 ast_set_flag(&(config.features_callee), AST_FEATURE_PLAY_WARNING);
1268 if (ast_test_flag(peerflags, DIAL_ALLOWREDIRECT_IN))
1269 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
1270 if (ast_test_flag(peerflags, DIAL_ALLOWREDIRECT_OUT))
1271 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
1272 if (ast_test_flag(peerflags, DIAL_ALLOWDISCONNECT_IN))
1273 ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
1274 if (ast_test_flag(peerflags, DIAL_ALLOWDISCONNECT_OUT))
1275 ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
1276 if (ast_test_flag(peerflags, DIAL_MONITOR_IN))
1277 ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
1278 if (ast_test_flag(peerflags, DIAL_MONITOR_OUT))
1279 ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
1281 config.timelimit = timelimit;
1282 config.play_warning = play_warning;
1283 config.warning_freq = warning_freq;
1284 config.warning_sound = warning_sound;
1285 config.end_sound = end_sound;
1286 config.start_sound = start_sound;
1290 } else if (sentringing) {
1292 ast_indicate(chan, -1);
1294 /* Be sure no generators are left on it */
1295 ast_deactivate_generator(chan);
1296 /* Make sure channels are compatible */
1297 res = ast_channel_make_compatible(chan, peer);
1299 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", chan->name, peer->name);
1303 res = ast_bridge_call(chan,peer,&config);
1305 snprintf(toast, sizeof(toast), "%ld", (long)(end_time - start_time));
1306 pbx_builtin_setvar_helper(chan, "DIALEDTIME", toast);
1307 snprintf(toast, sizeof(toast), "%ld", (long)(end_time - answer_time));
1308 pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", toast);
1313 if (res != AST_PBX_NO_HANGUP_PEER) {
1314 if (!chan->_softhangup)
1315 chan->hangupcause = peer->hangupcause;
1323 } else if (sentringing) {
1325 ast_indicate(chan, -1);
1327 hanguptree(outgoing, NULL);
1328 pbx_builtin_setvar_helper(chan, "DIALSTATUS", status);
1329 ast_log(LOG_DEBUG, "Exiting with DIALSTATUS=%s.\n", status);
1331 LOCAL_USER_REMOVE(u);
1333 if ((ast_test_flag(peerflags, DIAL_GO_ON)) && (!chan->_softhangup) && (res != AST_PBX_KEEPALIVE))
1339 static int dial_exec(struct ast_channel *chan, void *data)
1341 struct ast_flags peerflags;
1342 memset(&peerflags, 0, sizeof(peerflags));
1343 return dial_exec_full(chan, data, &peerflags);
1346 static int retrydial_exec(struct ast_channel *chan, void *data)
1348 char *announce = NULL, *context = NULL, *dialdata = NULL;
1349 int sleep = 0, loops = 0, res = 0;
1350 struct localuser *u = NULL;
1351 struct ast_flags peerflags;
1353 memset(&peerflags, 0, sizeof(peerflags));
1357 if (!data || !(announce = ast_strdupa(data))) {
1358 ast_log(LOG_ERROR, "Out of memory!\n");
1359 LOCAL_USER_REMOVE(u);
1363 if ((dialdata = strchr(announce, '|'))) {
1366 if ((sleep = atoi(dialdata))) {
1369 ast_log(LOG_ERROR, "%s requires the numerical argument <sleep>\n",rapp);
1370 LOCAL_USER_REMOVE(u);
1373 if ((dialdata = strchr(dialdata, '|'))) {
1376 if (!(loops = atoi(dialdata))) {
1377 ast_log(LOG_ERROR, "%s requires the numerical argument <loops>\n",rapp);
1378 LOCAL_USER_REMOVE(u);
1384 if ((dialdata = strchr(dialdata, '|'))) {
1388 ast_log(LOG_ERROR, "%s requires more arguments\n",rapp);
1389 LOCAL_USER_REMOVE(u);
1399 context = pbx_builtin_getvar_helper(chan, "EXITCONTEXT");
1402 chan->data = "Retrying";
1403 if (ast_test_flag(chan, AST_FLAG_MOH))
1406 if ((res = dial_exec_full(chan, dialdata, &peerflags)) == 0) {
1407 if (ast_test_flag(&peerflags, DIAL_HALT_ON_DTMF)) {
1408 if (!(res = ast_streamfile(chan, announce, chan->language)))
1409 res = ast_waitstream(chan, AST_DIGIT_ANY);
1410 if (!res && sleep) {
1411 if (!ast_test_flag(chan, AST_FLAG_MOH))
1412 ast_moh_start(chan, NULL);
1413 res = ast_waitfordigit(chan, sleep);
1416 if (!(res = ast_streamfile(chan, announce, chan->language)))
1417 res = ast_waitstream(chan, "");
1419 if (!ast_test_flag(chan, AST_FLAG_MOH))
1420 ast_moh_start(chan, NULL);
1422 res = ast_safe_sleep(chan, sleep);
1429 else if (res > 0) { /* Trying to send the call elsewhere (1 digit ext) */
1430 if (ast_onedigit_goto(chan, context, (char) res, 1, chan->cid.cid_num)) {
1438 if (ast_test_flag(chan, AST_FLAG_MOH))
1441 LOCAL_USER_REMOVE(u);
1442 return loops ? res : 0;
1446 int unload_module(void)
1448 STANDARD_HANGUP_LOCALUSERS;
1449 ast_unregister_application(app);
1450 return ast_unregister_application(rapp);
1453 int load_module(void)
1456 if (!(res = ast_register_application(app, dial_exec, synopsis, descrip)))
1457 res = ast_register_application(rapp, retrydial_exec, rsynopsis, rdescrip);
1461 char *description(void)
1469 STANDARD_USECOUNT(res);
1475 return ASTERISK_GPL_KEY;