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 " In addition to transferring the call, a call may be parked and then picked\n"
71 "up by another user.\n"
72 " The optional URL will be sent to the called party if the channel supports\n"
75 /* We define a customer "local user" structure because we
76 use it not only for keeping track of what is in use but
77 also for keeping track of who we're dialing. */
80 struct ast_channel *chan;
83 int allowredirect_out;
87 struct localuser *next;
92 static void hanguptree(struct localuser *outgoing, struct ast_channel *exception)
94 /* Hang up a tree of stuff */
97 /* Hangup any existing lines we have open */
98 if (outgoing->chan && (outgoing->chan != exception))
99 ast_hangup(outgoing->chan);
101 outgoing=outgoing->next;
108 static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localuser *outgoing, int *to, int *allowredir_in, int *allowredir_out, int *allowdisconnect)
117 struct ast_channel *peer = NULL;
118 struct ast_channel *watchers[MAX];
123 struct ast_channel *winner;
125 single = (outgoing && !outgoing->next && !outgoing->musiconhold && !outgoing->ringbackonly);
128 /* Turn off hold music, etc */
129 ast_indicate(in, -1);
130 /* If we are calling a single channel, make them compatible for in-band tone purpose */
131 ast_channel_make_compatible(outgoing->chan, in);
135 moh = outgoing->musiconhold;
136 ringind = outgoing->ringbackonly;
137 if (outgoing->musiconhold) {
138 ast_moh_start(in, NULL);
139 } else if (outgoing->ringbackonly) {
140 ast_indicate(in, AST_CONTROL_RINGING);
144 while(*to && !peer) {
151 /* Keep track of important channels */
152 if (o->stillgoing && o->chan) {
153 watchers[pos++] = o->chan;
160 if (numlines == numbusies) {
161 if (option_verbose > 2)
162 ast_verbose( VERBOSE_PREFIX_2 "Everyone is busy at this time\n");
163 /* See if there is a special busy message */
164 if (ast_exists_extension(in, in->context, in->exten, in->priority + 101, in->callerid))
167 if (option_verbose > 2)
168 ast_verbose( VERBOSE_PREFIX_2 "No one is available to answer at this time\n");
171 /* if no one available we'd better stop MOH/ringing to */
174 } else if (ringind) {
175 ast_indicate(in, -1);
179 winner = ast_waitfor_n(watchers, pos, to);
182 if (o->stillgoing && o->chan && (o->chan->_state == AST_STATE_UP)) {
184 if (option_verbose > 2)
185 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
187 *allowredir_in = o->allowredirect_in;
188 *allowredir_out = o->allowredirect_out;
189 *allowdisconnect = o->allowdisconnect;
191 } else if (o->chan && (o->chan == winner)) {
192 if (strlen(o->chan->call_forward)) {
194 /* Before processing channel, go ahead and check for forwarding */
195 if (option_verbose > 2)
196 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);
197 /* Setup parameters */
198 snprintf(tmpchan, sizeof(tmpchan),"%s@%s", o->chan->call_forward, o->chan->context);
200 o->chan = ast_request("Local", in->nativeformats, tmpchan);
202 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s'\n", tmpchan);
207 if (o->chan->callerid)
208 free(o->chan->callerid);
209 o->chan->callerid = malloc(strlen(in->callerid) + 1);
210 strncpy(o->chan->callerid, in->callerid, strlen(in->callerid) + 1);
215 o->chan->ani = malloc(strlen(in->ani) + 1);
216 strncpy(o->chan->ani, in->ani, strlen(in->ani) + 1);
218 if (ast_call(o->chan, tmpchan, 0)) {
219 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
228 f = ast_read(winner);
230 if (f->frametype == AST_FRAME_CONTROL) {
231 switch(f->subclass) {
232 case AST_CONTROL_ANSWER:
233 /* This is our guy if someone answered. */
235 if (option_verbose > 2)
236 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
238 *allowredir_in = o->allowredirect_in;
239 *allowredir_out = o->allowredirect_out;
240 *allowdisconnect = o->allowdisconnect;
243 case AST_CONTROL_BUSY:
244 if (option_verbose > 2)
245 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
246 in->hangupcause = o->chan->hangupcause;
251 ast_cdr_busy(in->cdr);
254 case AST_CONTROL_CONGESTION:
255 if (option_verbose > 2)
256 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
257 in->hangupcause = o->chan->hangupcause;
262 ast_cdr_busy(in->cdr);
265 case AST_CONTROL_RINGING:
266 if (option_verbose > 2)
267 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
268 if (!sentringing && !moh) {
269 ast_indicate(in, AST_CONTROL_RINGING);
274 case AST_CONTROL_PROGRESS:
275 if (option_verbose > 2)
276 ast_verbose ( VERBOSE_PREFIX_3 "%s is making progress passing it to %s\n", o->chan->name,in->name);
277 ast_indicate(in, AST_CONTROL_PROGRESS);
279 case AST_CONTROL_OFFHOOK:
280 /* Ignore going off hook */
283 if (option_verbose > 2)
284 ast_verbose( VERBOSE_PREFIX_3 "%s stopped sounds\n", o->chan->name);
285 ast_indicate(in, -1);
288 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
290 } else if (single && (f->frametype == AST_FRAME_VOICE) &&
291 !(outgoing->ringbackonly || outgoing->musiconhold)) {
292 if (ast_write(in, f))
293 ast_log(LOG_WARNING, "Unable to forward frame\n");
294 } else if (single && (f->frametype == AST_FRAME_IMAGE) &&
295 !(outgoing->ringbackonly || outgoing->musiconhold)) {
296 if (ast_write(in, f))
297 ast_log(LOG_WARNING, "Unable to forward image\n");
301 in->hangupcause = o->chan->hangupcause;
312 if (f && (f->frametype != AST_FRAME_VOICE))
313 printf("Frame type: %d, %d\n", f->frametype, f->subclass);
314 else if (!f || (f->frametype != AST_FRAME_VOICE))
315 printf("Hangup received on %s\n", in->name);
317 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
322 if (f && (f->frametype == AST_FRAME_DTMF) && *allowdisconnect &&
323 (f->subclass == '*')) {
324 if (option_verbose > 3)
325 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
329 if (single && ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_DTMF))) {
330 if (ast_write(outgoing->chan, f))
331 ast_log(LOG_WARNING, "Unable to forward voice\n");
335 if (!*to && (option_verbose > 2))
336 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
340 } else if (ringind) {
341 ast_indicate(in, -1);
348 static int dial_exec(struct ast_channel *chan, void *data)
352 char info[256], *peers, *timeout, *tech, *number, *rest, *cur;
353 char privdb[256] = "", *s;
354 char announcemsg[256] = "", *ann;
355 struct localuser *outgoing=NULL, *tmp;
356 struct ast_channel *peer;
359 int allowredir_out=0;
360 int allowdisconnect=0;
364 char numsubst[AST_MAX_EXTENSION];
365 char restofit[AST_MAX_EXTENSION];
366 char *transfer = NULL;
368 char callerid[256], *l, *n;
369 char *url=NULL; /* JDG */
370 struct ast_var_t *current;
371 struct varshead *headp, *newheadp;
372 struct ast_var_t *newvar;
376 ast_log(LOG_WARNING, "Dial requires an argument (technology1/number1&technology2/number2...|optional timeout)\n");
382 strncpy(info, (char *)data, sizeof(info) - 1);
385 timeout = strchr(info, '|');
389 transfer = strchr(timeout, '|');
394 url = strchr(transfer, '|');
398 ast_log(LOG_DEBUG, "DIAL WITH URL=%s_\n", url);
400 ast_log(LOG_DEBUG, "SIMPLE DIAL (NO URL)\n");
406 if (!peers || !strlen(peers)) {
407 ast_log(LOG_WARNING, "Dial argument takes format (technology1/number1&technology2/number2...|optional timeout)\n");
413 /* XXX ANNOUNCE SUPPORT */
414 if ((ann = strstr(transfer, "A("))) {
416 strncpy(announcemsg, ann + 2, sizeof(announcemsg) - 1);
417 /* Overwrite with X's what was the announce info */
418 while(*ann && (*ann != ')'))
422 /* Now find the end of the privdb */
423 ann = strchr(announcemsg, ')');
427 ast_log(LOG_WARNING, "Transfer with Announce spec lacking trailing ')'\n");
431 /* Extract privacy info from transfer */
432 if ((s = strstr(transfer, "P("))) {
434 strncpy(privdb, s + 2, sizeof(privdb) - 1);
435 /* Overwrite with X's what was the privacy info */
436 while(*s && (*s != ')'))
440 /* Now find the end of the privdb */
441 s = strchr(privdb, ')');
445 ast_log(LOG_WARNING, "Transfer with privacy lacking trailing ')'\n");
448 } else if (strchr(transfer, 'P')) {
449 /* No specified privdb */
451 } else if (strchr(transfer, 'C')) {
455 if (resetcdr && chan->cdr)
456 ast_cdr_reset(chan->cdr, 0);
457 if (!strlen(privdb) && privacy) {
458 /* If privdb is not specified and we are using privacy, copy from extension */
459 strncpy(privdb, chan->exten, sizeof(privdb) - 1);
463 strncpy(callerid, chan->callerid, sizeof(callerid));
465 strcpy(callerid, "");
466 ast_callerid_parse(callerid, &n, &l);
468 ast_shrink_phone_number(l);
471 ast_log(LOG_NOTICE, "Privacy DB is '%s', privacy is %d, clid is '%s'\n", privdb, privacy, l);
475 /* Remember where to start next time */
476 rest = strchr(cur, '&');
481 /* Get a technology/[device:]number pair */
483 number = strchr(tech, '/');
485 ast_log(LOG_WARNING, "Dial argument takes format (technology1/[device:]number1&technology2/[device:]number2...|optional timeout)\n");
490 tmp = malloc(sizeof(struct localuser));
492 ast_log(LOG_WARNING, "Out of memory\n");
495 memset(tmp, 0, sizeof(struct localuser));
497 if (strchr(transfer, 't'))
498 tmp->allowredirect_in = 1;
499 else tmp->allowredirect_in = 0;
500 if (strchr(transfer, 'T'))
501 tmp->allowredirect_out = 1;
502 else tmp->allowredirect_out = 0;
503 if (strchr(transfer, 'r'))
504 tmp->ringbackonly = 1;
505 else tmp->ringbackonly = 0;
506 if (strchr(transfer, 'm'))
507 tmp->musiconhold = 1;
508 else tmp->musiconhold = 0;
509 if (strchr(transfer, 'H'))
510 allowdisconnect = tmp->allowdisconnect = 1;
511 else allowdisconnect = tmp->allowdisconnect = 0;
512 if(strchr(transfer, 'g'))
515 strncpy(numsubst, number, sizeof(numsubst)-1);
516 /* If we're dialing by extension, look at the extension to know what to dial */
517 if ((newnum = strstr(numsubst, "BYEXTENSION"))) {
518 strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit)-1);
519 snprintf(newnum, sizeof(numsubst) - (newnum - numsubst), "%s%s", chan->exten,restofit);
521 ast_log(LOG_DEBUG, "Dialing by extension %s\n", numsubst);
523 /* Request the peer */
524 tmp->chan = ast_request(tech, chan->nativeformats, numsubst);
526 /* If we can't, just go on to the next call */
527 ast_log(LOG_NOTICE, "Unable to create channel of type '%s'\n", tech);
529 ast_cdr_busy(chan->cdr);
534 if (strlen(tmp->chan->call_forward)) {
536 if (option_verbose > 2)
537 ast_verbose(VERBOSE_PREFIX_3 "Forwarding call to '%s@%s'\n", tmp->chan->call_forward, tmp->chan->context);
538 snprintf(tmpchan, sizeof(tmpchan),"%s@%s", tmp->chan->call_forward, tmp->chan->context);
539 ast_hangup(tmp->chan);
540 tmp->chan = ast_request("Local", chan->nativeformats, tmpchan);
542 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s'\n", tmpchan);
548 /* If creating a SIP channel, look for a variable called */
549 /* VXML_URL in the calling channel and copy it to the */
551 if (strcasecmp(tech,"SIP")==0)
553 headp=&chan->varshead;
554 AST_LIST_TRAVERSE(headp,current,entries) {
555 if (strcasecmp(ast_var_name(current),"VXML_URL")==0)
557 newvar=ast_var_assign(ast_var_name(current),ast_var_value(current));
558 newheadp=&tmp->chan->varshead;
559 AST_LIST_INSERT_HEAD(newheadp,newvar,entries);
564 /* Check for ALERT_INFO in the SetVar list. This is for */
565 /* SIP distinctive ring as per the RFC. For Cisco 7960s, */
566 /* SetVar(ALERT_INFO=<x>) where x is an integer value 1-5. */
567 /* However, the RFC says it should be a URL. -km- */
569 if (strcasecmp(tech,"SIP")==0)
571 headp=&chan->varshead;
572 AST_LIST_TRAVERSE(headp,current,entries) {
573 /* Search for ALERT_INFO */
574 if (strcasecmp(ast_var_name(current),"ALERT_INFO")==0)
576 newvar=ast_var_assign(ast_var_name(current),ast_var_value(current));
577 newheadp=&tmp->chan->varshead;
578 AST_LIST_INSERT_HEAD(newheadp,newvar,entries);
584 tmp->chan->appl = "AppDial";
585 tmp->chan->data = "(Outgoing Line)";
586 tmp->chan->whentohangup = 0;
587 if (tmp->chan->callerid)
588 free(tmp->chan->callerid);
590 free(tmp->chan->ani);
592 tmp->chan->callerid = strdup(chan->callerid);
594 tmp->chan->callerid = NULL;
595 /* Copy language from incoming to outgoing */
596 strcpy(tmp->chan->language, chan->language);
597 if (!strlen(tmp->chan->musicclass))
598 strncpy(tmp->chan->musicclass, chan->musicclass, sizeof(tmp->chan->musicclass) - 1);
600 tmp->chan->ani = strdup(chan->ani);
602 tmp->chan->ani = NULL;
603 /* Pass hidecallerid setting */
604 tmp->chan->restrictcid = chan->restrictcid;
605 /* Pass callingpres setting */
606 tmp->chan->callingpres = chan->callingpres;
607 /* Presense of ADSI CPE on outgoing channel follows ours */
608 tmp->chan->adsicpe = chan->adsicpe;
609 /* pass the digital flag */
610 ast_dup_flag(tmp->chan, chan, AST_FLAG_DIGITAL);
611 /* Place the call, but don't wait on the answer */
612 res = ast_call(tmp->chan, numsubst, 0);
614 /* Save the info in cdr's that we called them */
616 ast_cdr_setdestchan(chan->cdr, tmp->chan->name);
618 /* check the restuls of ast_call */
620 /* Again, keep going even if there's an error */
622 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
623 else if (option_verbose > 2)
624 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", numsubst);
625 ast_hangup(tmp->chan);
630 if (option_verbose > 2)
631 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", numsubst);
632 /* Put them in the list of outgoing thingies... We're ready now.
633 XXX If we're forcibly removed, these outgoing calls won't get
635 tmp->stillgoing = -1;
636 tmp->next = outgoing;
638 /* If this line is up, don't try anybody else */
639 if (outgoing->chan->_state == AST_STATE_UP)
644 if (timeout && strlen(timeout))
645 to = atoi(timeout) * 1000;
648 peer = wait_for_answer(chan, outgoing, &to, &allowredir_in, &allowredir_out, &allowdisconnect);
651 /* Musta gotten hung up */
654 /* Nobody answered, next please? */
660 /* Ah ha! Someone answered within the desired timeframe. Of course after this
661 we will always return with -1 so that it is hung up properly after the
663 hanguptree(outgoing, peer);
665 /* If appropriate, log that we have a destination channel */
667 ast_cdr_setdestchan(chan->cdr, peer->name);
669 pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", peer->name);
671 pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", numsubst);
672 /* Make sure channels are compatible */
673 res = ast_channel_make_compatible(chan, peer);
675 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", chan->name, peer->name);
680 if( url && strlen(url) && ast_channel_supports_html(peer) ) {
681 ast_log(LOG_DEBUG, "app_dial: sendurl=%s.\n", url);
682 ast_channel_sendurl( peer, url );
684 if (announce && announcemsg)
687 // Start autoservice on the other chan
688 res2 = ast_autoservice_start(chan);
689 // Now Stream the File
691 res2 = ast_streamfile(peer,announcemsg,peer->language);
693 res2 = ast_waitstream(peer,"");
694 // Ok, done. stop autoservice
695 res2 = ast_autoservice_stop(chan);
697 res = ast_bridge_call(chan, peer, allowredir_in, allowredir_out, allowdisconnect);
699 if (res != AST_PBX_NO_HANGUP_PEER)
703 hanguptree(outgoing, NULL);
704 LOCAL_USER_REMOVE(u);
706 if((go_on>0) && (!chan->_softhangup))
712 int unload_module(void)
714 STANDARD_HANGUP_LOCALUSERS;
715 return ast_unregister_application(app);
718 int load_module(void)
721 res = ast_register_application(app, dial_exec, synopsis, descrip);
725 char *description(void)
733 STANDARD_USECOUNT(res);
739 return ASTERISK_GPL_KEY;