2 * Asterisk -- A telephony toolkit for Linux.
4 * Trivial application to dial a channel and send an URL on answer
6 * Copyright (C) 1999, Mark Spencer
8 * Mark Spencer <markster@linux-support.net>
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/parking.h>
24 #include <asterisk/musiconhold.h>
25 #include <asterisk/callerid.h>
33 #include <sys/signal.h>
34 #include <netinet/in.h>
38 static char *tdesc = "Dialing Application";
40 static char *app = "Dial";
42 static char *synopsis = "Place a call and connect to the current channel";
44 static char *descrip =
45 " Dial(Technology/resource[&Technology2/resource2...][|timeout][|options][|URL]):\n"
46 "Requests one or more channels and places specified outgoing calls on them.\n"
47 "As soon as a channel answers, the Dial app will answer the originating\n"
48 "channel (if it needs to be answered) and will bridge a call with the channel\n"
49 "which first answered. All other calls placed by the Dial app will be hung up\n"
50 "If a timeout is not specified, the Dial application will wait indefinitely\n"
51 "until either one of the called channels answers, the user hangs up, or all\n"
52 "channels return busy or error. In general, the dialer will return 0 if it\n"
53 "was unable to place the call, or the timeout expired. However, if all\n"
54 "channels were busy, and there exists an extension with priority n+101 (where\n"
55 "n is the priority of the dialer instance), then it will be the next\n"
56 "executed extension (this allows you to setup different behavior on busy from\n"
58 " This application returns -1 if the originating channel hangs up, or if the\n"
59 "call is bridged and either of the parties in the bridge terminate the call.\n"
60 "The option string may contain zero or more of the following characters:\n"
61 " 't' -- allow the called user transfer the calling user\n"
62 " 'T' -- to allow the calling user to transfer the call.\n"
63 " 'r' -- indicate ringing to the calling party, pass no audio until answered.\n"
64 " 'm' -- provide hold music to the calling party until answered.\n"
65 " 'H' -- allow caller to hang up by hitting *.\n"
66 " 'C' -- reset call detail record for this call.\n"
67 " 'P[(x)]' -- privacy mode, using 'x' as database if provided.\n"
68 " 'g' -- goes on in context if the destination channel hangs up\n"
69 " 'A(x)' -- play an announcement to the called party, using x as file\n"
70 " 'S(x)' -- hangup the call after x seconds AFTER called party picked up\n"
71 " In addition to transferring the call, a call may be parked and then picked\n"
72 "up by another user.\n"
73 " The optional URL will be sent to the called party if the channel supports\n"
76 /* We define a customer "local user" structure because we
77 use it not only for keeping track of what is in use but
78 also for keeping track of who we're dialing. */
81 struct ast_channel *chan;
84 int allowredirect_out;
88 struct localuser *next;
93 static void hanguptree(struct localuser *outgoing, struct ast_channel *exception)
95 /* Hang up a tree of stuff */
98 /* Hangup any existing lines we have open */
99 if (outgoing->chan && (outgoing->chan != exception))
100 ast_hangup(outgoing->chan);
102 outgoing=outgoing->next;
109 static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localuser *outgoing, int *to, int *allowredir_in, int *allowredir_out, int *allowdisconnect)
118 struct ast_channel *peer = NULL;
119 struct ast_channel *watchers[MAX];
124 struct ast_channel *winner;
126 single = (outgoing && !outgoing->next && !outgoing->musiconhold && !outgoing->ringbackonly);
129 /* Turn off hold music, etc */
130 ast_indicate(in, -1);
131 /* If we are calling a single channel, make them compatible for in-band tone purpose */
132 ast_channel_make_compatible(outgoing->chan, in);
136 moh = outgoing->musiconhold;
137 ringind = outgoing->ringbackonly;
138 if (outgoing->musiconhold) {
139 ast_moh_start(in, NULL);
140 } else if (outgoing->ringbackonly) {
141 ast_indicate(in, AST_CONTROL_RINGING);
146 while(*to && !peer) {
153 /* Keep track of important channels */
154 if (o->stillgoing && o->chan) {
155 watchers[pos++] = o->chan;
162 if (numlines == numbusies) {
163 if (option_verbose > 2)
164 ast_verbose( VERBOSE_PREFIX_2 "Everyone is busy at this time\n");
165 /* See if there is a special busy message */
166 if (ast_exists_extension(in, in->context, in->exten, in->priority + 101, in->callerid))
169 if (option_verbose > 2)
170 ast_verbose( VERBOSE_PREFIX_2 "No one is available to answer at this time\n");
173 /* if no one available we'd better stop MOH/ringing to */
176 } else if (sentringing) {
177 ast_indicate(in, -1);
181 winner = ast_waitfor_n(watchers, pos, to);
184 if (o->stillgoing && o->chan && (o->chan->_state == AST_STATE_UP)) {
186 if (option_verbose > 2)
187 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
189 *allowredir_in = o->allowredirect_in;
190 *allowredir_out = o->allowredirect_out;
191 *allowdisconnect = o->allowdisconnect;
193 } else if (o->chan && (o->chan == winner)) {
194 if (strlen(o->chan->call_forward)) {
196 /* Before processing channel, go ahead and check for forwarding */
197 if (option_verbose > 2)
198 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s@%s' (thanks to %s)\n", in->name, o->chan->call_forward, o->chan->context, o->chan->name);
199 /* Setup parameters */
200 snprintf(tmpchan, sizeof(tmpchan),"%s@%s", o->chan->call_forward, o->chan->context);
202 o->chan = ast_request("Local", in->nativeformats, tmpchan);
204 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s'\n", tmpchan);
209 if (o->chan->callerid)
210 free(o->chan->callerid);
211 o->chan->callerid = malloc(strlen(in->callerid) + 1);
212 if (o->chan->callerid)
213 strncpy(o->chan->callerid, in->callerid, strlen(in->callerid) + 1);
215 ast_log(LOG_WARNING, "Out of memory\n");
220 o->chan->ani = malloc(strlen(in->ani) + 1);
222 strncpy(o->chan->ani, in->ani, strlen(in->ani) + 1);
224 ast_log(LOG_WARNING, "Out of memory\n");
227 free(o->chan->rdnis);
228 if (strlen(in->macroexten))
229 o->chan->rdnis = strdup(in->macroexten);
231 o->chan->rdnis = strdup(in->exten);
232 if (ast_call(o->chan, tmpchan, 0)) {
233 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
242 f = ast_read(winner);
244 if (f->frametype == AST_FRAME_CONTROL) {
245 switch(f->subclass) {
246 case AST_CONTROL_ANSWER:
247 /* This is our guy if someone answered. */
249 if (option_verbose > 2)
250 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
252 *allowredir_in = o->allowredirect_in;
253 *allowredir_out = o->allowredirect_out;
254 *allowdisconnect = o->allowdisconnect;
257 case AST_CONTROL_BUSY:
258 if (option_verbose > 2)
259 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
260 in->hangupcause = o->chan->hangupcause;
265 ast_cdr_busy(in->cdr);
268 case AST_CONTROL_CONGESTION:
269 if (option_verbose > 2)
270 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
271 in->hangupcause = o->chan->hangupcause;
276 ast_cdr_busy(in->cdr);
279 case AST_CONTROL_RINGING:
280 if (option_verbose > 2)
281 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
282 if (!sentringing && !moh) {
283 ast_indicate(in, AST_CONTROL_RINGING);
287 case AST_CONTROL_PROGRESS:
288 if (option_verbose > 2)
289 ast_verbose ( VERBOSE_PREFIX_3 "%s is making progress passing it to %s\n", o->chan->name,in->name);
290 ast_indicate(in, AST_CONTROL_PROGRESS);
292 case AST_CONTROL_OFFHOOK:
293 /* Ignore going off hook */
296 if (!ringind && !moh) {
297 if (option_verbose > 2)
298 ast_verbose( VERBOSE_PREFIX_3 "%s stopped sounds\n", o->chan->name);
299 ast_indicate(in, -1);
304 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
306 } else if (single && (f->frametype == AST_FRAME_VOICE) &&
307 !(outgoing->ringbackonly || outgoing->musiconhold)) {
308 if (ast_write(in, f))
309 ast_log(LOG_WARNING, "Unable to forward frame\n");
310 } else if (single && (f->frametype == AST_FRAME_IMAGE) &&
311 !(outgoing->ringbackonly || outgoing->musiconhold)) {
312 if (ast_write(in, f))
313 ast_log(LOG_WARNING, "Unable to forward image\n");
317 in->hangupcause = o->chan->hangupcause;
328 if (f && (f->frametype != AST_FRAME_VOICE))
329 printf("Frame type: %d, %d\n", f->frametype, f->subclass);
330 else if (!f || (f->frametype != AST_FRAME_VOICE))
331 printf("Hangup received on %s\n", in->name);
333 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
338 if (f && (f->frametype == AST_FRAME_DTMF) && *allowdisconnect &&
339 (f->subclass == '*')) {
340 if (option_verbose > 3)
341 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
345 if (single && ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_DTMF))) {
346 if (ast_write(outgoing->chan, f))
347 ast_log(LOG_WARNING, "Unable to forward voice\n");
351 if (!*to && (option_verbose > 2))
352 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
356 } else if (sentringing) {
357 ast_indicate(in, -1);
364 static int dial_exec(struct ast_channel *chan, void *data)
368 char info[256], *peers, *timeout, *tech, *number, *rest, *cur;
369 char privdb[256] = "", *s;
370 char announcemsg[256] = "", *ann;
371 struct localuser *outgoing=NULL, *tmp;
372 struct ast_channel *peer;
375 int allowredir_out=0;
376 int allowdisconnect=0;
380 char numsubst[AST_MAX_EXTENSION];
381 char restofit[AST_MAX_EXTENSION];
382 char *transfer = NULL;
384 char callerid[256], *l, *n;
385 char *url=NULL; /* JDG */
386 struct ast_var_t *current;
387 struct varshead *headp, *newheadp;
388 struct ast_var_t *newvar;
390 unsigned int calldurationlimit=0;
395 ast_log(LOG_WARNING, "Dial requires an argument (technology1/number1&technology2/number2...|optional timeout|options)\n");
401 strncpy(info, (char *)data, sizeof(info) - 1);
405 timeout = strchr(info, '|');
409 transfer = strchr(timeout, '|');
414 url = strchr(transfer, '|');
418 ast_log(LOG_DEBUG, "DIAL WITH URL=%s_\n", url);
420 ast_log(LOG_DEBUG, "SIMPLE DIAL (NO URL)\n");
426 if (!peers || !strlen(peers)) {
427 ast_log(LOG_WARNING, "Dial argument takes format (technology1/number1&technology2/number2...|optional timeout)\n");
433 /* Extract call duration limit */
434 if ((cdl = strstr(transfer, "S("))) {
435 calldurationlimit=atoi(cdl+2);
436 if (option_verbose > 2)
437 ast_verbose(VERBOSE_PREFIX_3 "Setting call duration limit to %i seconds.\n",calldurationlimit);
440 /* XXX ANNOUNCE SUPPORT */
441 if ((ann = strstr(transfer, "A("))) {
443 strncpy(announcemsg, ann + 2, sizeof(announcemsg) - 1);
444 /* Overwrite with X's what was the announce info */
445 while(*ann && (*ann != ')'))
449 /* Now find the end of the privdb */
450 ann = strchr(announcemsg, ')');
454 ast_log(LOG_WARNING, "Transfer with Announce spec lacking trailing ')'\n");
458 /* Extract privacy info from transfer */
459 if ((s = strstr(transfer, "P("))) {
461 strncpy(privdb, s + 2, sizeof(privdb) - 1);
462 /* Overwrite with X's what was the privacy info */
463 while(*s && (*s != ')'))
467 /* Now find the end of the privdb */
468 s = strchr(privdb, ')');
472 ast_log(LOG_WARNING, "Transfer with privacy lacking trailing ')'\n");
475 } else if (strchr(transfer, 'P')) {
476 /* No specified privdb */
478 } else if (strchr(transfer, 'C')) {
482 if (resetcdr && chan->cdr)
483 ast_cdr_reset(chan->cdr, 0);
484 if (!strlen(privdb) && privacy) {
485 /* If privdb is not specified and we are using privacy, copy from extension */
486 strncpy(privdb, chan->exten, sizeof(privdb) - 1);
490 strncpy(callerid, chan->callerid, sizeof(callerid));
492 strcpy(callerid, "");
493 ast_callerid_parse(callerid, &n, &l);
495 ast_shrink_phone_number(l);
498 ast_log(LOG_NOTICE, "Privacy DB is '%s', privacy is %d, clid is '%s'\n", privdb, privacy, l);
502 /* Remember where to start next time */
503 rest = strchr(cur, '&');
508 /* Get a technology/[device:]number pair */
510 number = strchr(tech, '/');
512 ast_log(LOG_WARNING, "Dial argument takes format (technology1/[device:]number1&technology2/[device:]number2...|optional timeout)\n");
517 tmp = malloc(sizeof(struct localuser));
519 ast_log(LOG_WARNING, "Out of memory\n");
522 memset(tmp, 0, sizeof(struct localuser));
524 if (strchr(transfer, 't'))
525 tmp->allowredirect_in = 1;
526 else tmp->allowredirect_in = 0;
527 if (strchr(transfer, 'T'))
528 tmp->allowredirect_out = 1;
529 else tmp->allowredirect_out = 0;
530 if (strchr(transfer, 'r'))
531 tmp->ringbackonly = 1;
532 else tmp->ringbackonly = 0;
533 if (strchr(transfer, 'm'))
534 tmp->musiconhold = 1;
535 else tmp->musiconhold = 0;
536 if (strchr(transfer, 'H'))
537 allowdisconnect = tmp->allowdisconnect = 1;
538 else allowdisconnect = tmp->allowdisconnect = 0;
539 if(strchr(transfer, 'g'))
542 strncpy(numsubst, number, sizeof(numsubst)-1);
543 /* If we're dialing by extension, look at the extension to know what to dial */
544 if ((newnum = strstr(numsubst, "BYEXTENSION"))) {
545 strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit)-1);
546 snprintf(newnum, sizeof(numsubst) - (newnum - numsubst), "%s%s", chan->exten,restofit);
548 ast_log(LOG_DEBUG, "Dialing by extension %s\n", numsubst);
550 /* Request the peer */
551 tmp->chan = ast_request(tech, chan->nativeformats, numsubst);
553 /* If we can't, just go on to the next call */
554 ast_log(LOG_NOTICE, "Unable to create channel of type '%s'\n", tech);
556 ast_cdr_busy(chan->cdr);
561 if (strlen(tmp->chan->call_forward)) {
563 if (option_verbose > 2)
564 ast_verbose(VERBOSE_PREFIX_3 "Forwarding call to '%s@%s'\n", tmp->chan->call_forward, tmp->chan->context);
565 snprintf(tmpchan, sizeof(tmpchan),"%s@%s", tmp->chan->call_forward, tmp->chan->context);
566 ast_hangup(tmp->chan);
567 tmp->chan = ast_request("Local", chan->nativeformats, tmpchan);
569 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s'\n", tmpchan);
575 /* If creating a SIP channel, look for a variable called */
576 /* VXML_URL in the calling channel and copy it to the */
578 if (strcasecmp(tech,"SIP")==0)
580 headp=&chan->varshead;
581 AST_LIST_TRAVERSE(headp,current,entries) {
582 if (strcasecmp(ast_var_name(current),"VXML_URL")==0)
584 newvar=ast_var_assign(ast_var_name(current),ast_var_value(current));
585 newheadp=&tmp->chan->varshead;
586 AST_LIST_INSERT_HEAD(newheadp,newvar,entries);
591 /* Check for ALERT_INFO in the SetVar list. This is for */
592 /* SIP distinctive ring as per the RFC. For Cisco 7960s, */
593 /* SetVar(ALERT_INFO=<x>) where x is an integer value 1-5. */
594 /* However, the RFC says it should be a URL. -km- */
596 if (strcasecmp(tech,"SIP")==0)
598 headp=&chan->varshead;
599 AST_LIST_TRAVERSE(headp,current,entries) {
600 /* Search for ALERT_INFO */
601 if (strcasecmp(ast_var_name(current),"ALERT_INFO")==0)
603 newvar=ast_var_assign(ast_var_name(current),ast_var_value(current));
604 newheadp=&tmp->chan->varshead;
605 AST_LIST_INSERT_HEAD(newheadp,newvar,entries);
611 tmp->chan->appl = "AppDial";
612 tmp->chan->data = "(Outgoing Line)";
613 tmp->chan->whentohangup = 0;
614 if (tmp->chan->callerid)
615 free(tmp->chan->callerid);
617 free(tmp->chan->ani);
619 tmp->chan->callerid = strdup(chan->callerid);
621 tmp->chan->callerid = NULL;
622 /* Copy language from incoming to outgoing */
623 strcpy(tmp->chan->language, chan->language);
624 if (!strlen(tmp->chan->musicclass))
625 strncpy(tmp->chan->musicclass, chan->musicclass, sizeof(tmp->chan->musicclass) - 1);
627 tmp->chan->ani = strdup(chan->ani);
629 tmp->chan->ani = NULL;
630 /* Pass hidecallerid setting */
631 tmp->chan->restrictcid = chan->restrictcid;
632 /* Pass callingpres setting */
633 tmp->chan->callingpres = chan->callingpres;
634 /* Presense of ADSI CPE on outgoing channel follows ours */
635 tmp->chan->adsicpe = chan->adsicpe;
636 /* pass the digital flag */
637 ast_dup_flag(tmp->chan, chan, AST_FLAG_DIGITAL);
638 /* Place the call, but don't wait on the answer */
639 res = ast_call(tmp->chan, numsubst, 0);
641 /* Save the info in cdr's that we called them */
643 ast_cdr_setdestchan(chan->cdr, tmp->chan->name);
645 /* check the restuls of ast_call */
647 /* Again, keep going even if there's an error */
649 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
650 else if (option_verbose > 2)
651 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", numsubst);
652 ast_hangup(tmp->chan);
657 if (option_verbose > 2)
658 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", numsubst);
659 /* Put them in the list of outgoing thingies... We're ready now.
660 XXX If we're forcibly removed, these outgoing calls won't get
662 tmp->stillgoing = -1;
663 tmp->next = outgoing;
665 /* If this line is up, don't try anybody else */
666 if (outgoing->chan->_state == AST_STATE_UP)
671 if (timeout && strlen(timeout))
672 to = atoi(timeout) * 1000;
675 peer = wait_for_answer(chan, outgoing, &to, &allowredir_in, &allowredir_out, &allowdisconnect);
678 /* Musta gotten hung up */
681 /* Nobody answered, next please? */
687 /* Ah ha! Someone answered within the desired timeframe. Of course after this
688 we will always return with -1 so that it is hung up properly after the
690 hanguptree(outgoing, peer);
692 /* If appropriate, log that we have a destination channel */
694 ast_cdr_setdestchan(chan->cdr, peer->name);
696 pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", peer->name);
698 pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", numsubst);
699 /* Make sure channels are compatible */
700 res = ast_channel_make_compatible(chan, peer);
702 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", chan->name, peer->name);
707 if( url && strlen(url) && ast_channel_supports_html(peer) ) {
708 ast_log(LOG_DEBUG, "app_dial: sendurl=%s.\n", url);
709 ast_channel_sendurl( peer, url );
711 if (announce && announcemsg)
714 // Start autoservice on the other chan
715 res2 = ast_autoservice_start(chan);
716 // Now Stream the File
718 res2 = ast_streamfile(peer,announcemsg,peer->language);
720 res2 = ast_waitstream(peer,"");
721 // Ok, done. stop autoservice
722 res2 = ast_autoservice_stop(chan);
724 if (calldurationlimit > 0) {
726 chan->whentohangup = now + calldurationlimit;
728 res = ast_bridge_call(chan, peer, allowredir_in, allowredir_out, allowdisconnect);
730 if (res != AST_PBX_NO_HANGUP_PEER)
734 hanguptree(outgoing, NULL);
735 LOCAL_USER_REMOVE(u);
737 if((go_on>0) && (!chan->_softhangup))
743 int unload_module(void)
745 STANDARD_HANGUP_LOCALUSERS;
746 return ast_unregister_application(app);
749 int load_module(void)
752 res = ast_register_application(app, dial_exec, synopsis, descrip);
756 char *description(void)
764 STANDARD_USECOUNT(res);
770 return ASTERISK_GPL_KEY;