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 an 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 hunp 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 dialler 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 dialler 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 " 'd' -- data-quality (modem) call (minimum delay).\n"
66 " 'c' -- clear-channel data call (PRI-PRI only).\n"
67 " 'H' -- allow caller to hang up by hitting *.\n"
68 " 'C' -- reset call detail record for this call.\n"
69 " 'P[(x)]' -- privacy mode, using 'x' as database if provided.\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 optionnal 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;
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 /* If we are calling a single channel, make them compatible for in-band tone purpose */
130 ast_channel_make_compatible(outgoing->chan, in);
134 moh = outgoing->musiconhold;
135 ringind = outgoing->ringbackonly;
136 if (outgoing->musiconhold) {
137 ast_moh_start(in, NULL);
138 } else if (outgoing->ringbackonly) {
139 ast_indicate(in, AST_CONTROL_RINGING);
143 while(*to && !peer) {
150 /* Keep track of important channels */
151 if (o->stillgoing && o->chan) {
152 watchers[pos++] = o->chan;
159 if (numlines == numbusies) {
160 if (option_verbose > 2)
161 ast_verbose( VERBOSE_PREFIX_2 "Everyone is busy at this time\n");
162 /* See if there is a special busy message */
163 if (ast_exists_extension(in, in->context, in->exten, in->priority + 101, in->callerid))
166 if (option_verbose > 2)
167 ast_verbose( VERBOSE_PREFIX_2 "No one is available to answer at this time\n");
170 /* if no one available we'd better stop MOH/ringing to */
173 } else if (ringind) {
174 ast_indicate(in, -1);
178 winner = ast_waitfor_n(watchers, pos, to);
181 if (o->stillgoing && (o->chan->_state == AST_STATE_UP)) {
183 if (option_verbose > 2)
184 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
186 *allowredir_in = o->allowredirect_in;
187 *allowredir_out = o->allowredirect_out;
188 *allowdisconnect = o->allowdisconnect;
190 } else if (o->chan == winner) {
191 if (strlen(o->chan->call_forward)) {
193 /* Before processing channel, go ahead and check for forwarding */
194 if (option_verbose > 2)
195 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);
196 /* Setup parameters */
197 snprintf(tmpchan, sizeof(tmpchan),"%s@%s", o->chan->call_forward, o->chan->context);
199 o->chan = ast_request("Local", in->nativeformats, tmpchan);
201 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s'\n", tmpchan);
204 } else if (ast_call(o->chan, tmpchan, 0)) {
205 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
213 f = ast_read(winner);
215 if (f->frametype == AST_FRAME_CONTROL) {
216 switch(f->subclass) {
217 case AST_CONTROL_ANSWER:
218 /* This is our guy if someone answered. */
220 if (option_verbose > 2)
221 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
223 *allowredir_in = o->allowredirect_in;
224 *allowredir_out = o->allowredirect_out;
225 *allowdisconnect = o->allowdisconnect;
228 case AST_CONTROL_BUSY:
229 if (option_verbose > 2)
230 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
235 ast_cdr_busy(in->cdr);
238 case AST_CONTROL_CONGESTION:
239 if (option_verbose > 2)
240 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
245 ast_cdr_busy(in->cdr);
248 case AST_CONTROL_RINGING:
249 if (option_verbose > 2)
250 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
251 if (!sentringing && !moh) {
252 ast_indicate(in, AST_CONTROL_RINGING);
257 case AST_CONTROL_PROGRESS:
258 if (option_verbose > 2)
259 ast_verbose ( VERBOSE_PREFIX_3 "%s is making progress passing it to %s\n", o->chan->name,in->name);
260 ast_indicate(in, AST_CONTROL_PROGRESS);
262 case AST_CONTROL_OFFHOOK:
263 /* Ignore going off hook */
266 if (option_verbose > 2)
267 ast_verbose( VERBOSE_PREFIX_3 "%s stopped sounds\n", o->chan->name);
268 ast_indicate(in, -1);
271 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
273 } else if (single && (f->frametype == AST_FRAME_VOICE) &&
274 !(outgoing->ringbackonly || outgoing->musiconhold)) {
275 if (ast_write(in, f))
276 ast_log(LOG_WARNING, "Unable to forward frame\n");
277 } else if (single && (f->frametype == AST_FRAME_IMAGE) &&
278 !(outgoing->ringbackonly || outgoing->musiconhold)) {
279 if (ast_write(in, f))
280 ast_log(LOG_WARNING, "Unable to forward image\n");
294 if (f && (f->frametype != AST_FRAME_VOICE))
295 printf("Frame type: %d, %d\n", f->frametype, f->subclass);
296 else if (!f || (f->frametype != AST_FRAME_VOICE))
297 printf("Hangup received on %s\n", in->name);
299 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
304 if (f && (f->frametype == AST_FRAME_DTMF) && *allowdisconnect &&
305 (f->subclass == '*')) {
306 if (option_verbose > 3)
307 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
311 if (single && ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_DTMF))) {
312 if (ast_write(outgoing->chan, f))
313 ast_log(LOG_WARNING, "Unable to forward voice\n");
317 if (!*to && (option_verbose > 2))
318 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
322 } else if (ringind) {
323 ast_indicate(in, -1);
330 static int dial_exec(struct ast_channel *chan, void *data)
334 char info[256], *peers, *timeout, *tech, *number, *rest, *cur;
335 char privdb[256] = "", *s;
336 struct localuser *outgoing=NULL, *tmp;
337 struct ast_channel *peer;
340 int allowredir_out=0;
341 int allowdisconnect=0;
345 char numsubst[AST_MAX_EXTENSION];
346 char restofit[AST_MAX_EXTENSION];
347 char *transfer = NULL;
349 char callerid[256], *l, *n;
350 char *url=NULL; /* JDG */
351 struct ast_var_t *current;
352 struct varshead *headp, *newheadp;
353 struct ast_var_t *newvar;
356 ast_log(LOG_WARNING, "Dial requires an argument (technology1/number1&technology2/number2...|optional timeout)\n");
362 /* Parse our arguments XXX Check for failure XXX */
363 strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
366 timeout = strchr(info, '|');
370 transfer = strchr(timeout, '|');
375 url = strchr(transfer, '|');
379 ast_log(LOG_DEBUG, "DIAL WITH URL=%s_\n", url);
381 ast_log(LOG_DEBUG, "SIMPLE DIAL (NO URL)\n");
387 if (!peers || !strlen(peers)) {
388 ast_log(LOG_WARNING, "Dial argument takes format (technology1/number1&technology2/number2...|optional timeout)\n");
394 /* Extract privacy info from transfer */
395 if ((s = strstr(transfer, "P("))) {
397 strncpy(privdb, s + 2, sizeof(privdb) - 1);
398 /* Overwrite with X's what was the privacy info */
399 while(*s && (*s != ')'))
403 /* Now find the end of the privdb */
404 s = strchr(privdb, ')');
408 ast_log(LOG_WARNING, "Transfer with privacy lacking trailing '('\n");
411 } else if (strchr(transfer, 'P')) {
412 /* No specified privdb */
414 } else if (strchr(transfer, 'C')) {
418 if (resetcdr && chan->cdr)
419 ast_cdr_reset(chan->cdr, 0);
420 if (!strlen(privdb) && privacy) {
421 /* If privdb is not specified and we are using privacy, copy from extension */
422 strncpy(privdb, chan->exten, sizeof(privdb) - 1);
426 strncpy(callerid, chan->callerid, sizeof(callerid));
428 strcpy(callerid, "");
429 ast_callerid_parse(callerid, &n, &l);
431 ast_shrink_phone_number(l);
434 ast_log(LOG_NOTICE, "Privacy DB is '%s', privacy is %d, clid is '%s'\n", privdb, privacy, l);
438 /* Remember where to start next time */
439 rest = strchr(cur, '&');
444 /* Get a technology/[device:]number pair */
446 number = strchr(tech, '/');
448 ast_log(LOG_WARNING, "Dial argument takes format (technology1/[device:]number1&technology2/[device:]number2...|optional timeout)\n");
453 tmp = malloc(sizeof(struct localuser));
455 ast_log(LOG_WARNING, "Out of memory\n");
458 memset(tmp, 0, sizeof(struct localuser));
460 if (strchr(transfer, 't'))
461 tmp->allowredirect_in = 1;
462 else tmp->allowredirect_in = 0;
463 if (strchr(transfer, 'T'))
464 tmp->allowredirect_out = 1;
465 else tmp->allowredirect_out = 0;
466 if (strchr(transfer, 'r'))
467 tmp->ringbackonly = 1;
468 else tmp->ringbackonly = 0;
469 if (strchr(transfer, 'm'))
470 tmp->musiconhold = 1;
471 else tmp->musiconhold = 0;
472 if (strchr(transfer, 'd'))
473 tmp->dataquality = 1;
474 else tmp->dataquality = 0;
475 if (strchr(transfer, 'H'))
476 allowdisconnect = tmp->allowdisconnect = 1;
477 else allowdisconnect = tmp->allowdisconnect = 0;
478 if (strchr(transfer, 'c'))
483 strncpy(numsubst, number, sizeof(numsubst)-1);
484 /* If we're dialing by extension, look at the extension to know what to dial */
485 if ((newnum = strstr(numsubst, "BYEXTENSION"))) {
486 strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit)-1);
487 snprintf(newnum, sizeof(numsubst) - (newnum - numsubst), "%s%s", chan->exten,restofit);
489 ast_log(LOG_DEBUG, "Dialing by extension %s\n", numsubst);
491 /* Request the peer */
492 tmp->chan = ast_request(tech, chan->nativeformats, numsubst);
494 /* If we can't, just go on to the next call */
495 ast_log(LOG_NOTICE, "Unable to create channel of type '%s'\n", tech);
497 ast_cdr_busy(chan->cdr);
502 if (strlen(tmp->chan->call_forward)) {
504 if (option_verbose > 2)
505 ast_verbose(VERBOSE_PREFIX_3 "Forwarding call to '%s@%s'\n", tmp->chan->call_forward, tmp->chan->context);
506 snprintf(tmpchan, sizeof(tmpchan),"%s@%s", tmp->chan->call_forward, tmp->chan->context);
507 ast_hangup(tmp->chan);
508 tmp->chan = ast_request("Local", chan->nativeformats, tmpchan);
510 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s'\n", tmpchan);
516 /* If creating a SIP channel, look for a variable called */
517 /* VXML_URL in the calling channel and copy it to the */
519 if (strcasecmp(tech,"SIP")==0)
521 headp=&chan->varshead;
522 AST_LIST_TRAVERSE(headp,current,entries) {
523 if (strcasecmp(ast_var_name(current),"VXML_URL")==0)
525 newvar=ast_var_assign(ast_var_name(current),ast_var_value(current));
526 newheadp=&tmp->chan->varshead;
527 AST_LIST_INSERT_HEAD(newheadp,newvar,entries);
532 /* Check for ALERT_INFO in the SetVar list. This is for */
533 /* SIP distinctive ring as per the RFC. For Cisco 7960s, */
534 /* SetVar(ALERT_INFO=<x>) where x is an integer. However, */
535 /* the RFC says it should be a URL. -- km- */
537 if (strcasecmp(tech,"SIP")==0)
539 headp=&chan->varshead;
540 AST_LIST_TRAVERSE(headp,current,entries) {
541 /* Search for ALERT_INFO */
542 if (strcasecmp(ast_var_name(current),"ALERT_INFO")==0)
544 newvar=ast_var_assign(ast_var_name(current),ast_var_value(current));
545 newheadp=&tmp->chan->varshead;
546 AST_LIST_INSERT_HEAD(newheadp,newvar,entries);
552 tmp->chan->appl = "AppDial";
553 tmp->chan->data = "(Outgoing Line)";
554 tmp->chan->whentohangup = 0;
555 if (tmp->chan->callerid)
556 free(tmp->chan->callerid);
558 free(tmp->chan->ani);
560 tmp->chan->callerid = strdup(chan->callerid);
562 tmp->chan->callerid = NULL;
564 tmp->chan->ani = strdup(chan->ani);
566 tmp->chan->ani = NULL;
567 /* Presense of ADSI CPE on outgoing channel follows ours */
568 tmp->chan->adsicpe = chan->adsicpe;
569 /* Place the call, but don't wait on the answer */
570 res = ast_call(tmp->chan, numsubst, 0);
572 /* Again, keep going even if there's an error */
574 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
575 else if (option_verbose > 2)
576 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", numsubst);
577 ast_hangup(tmp->chan);
582 if (option_verbose > 2)
583 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", numsubst);
584 /* Put them in the list of outgoing thingies... We're ready now.
585 XXX If we're forcibly removed, these outgoing calls won't get
587 tmp->stillgoing = -1;
588 tmp->next = outgoing;
590 /* If this line is up, don't try anybody else */
591 if (outgoing->chan->_state == AST_STATE_UP)
596 if (timeout && strlen(timeout))
597 to = atoi(timeout) * 1000;
600 peer = wait_for_answer(chan, outgoing, &to, &allowredir_in, &allowredir_out, &allowdisconnect);
603 /* Musta gotten hung up */
606 /* Nobody answered, next please? */
612 /* Ah ha! Someone answered within the desired timeframe. Of course after this
613 we will always return with -1 so that it is hung up properly after the
615 if (!strcmp(chan->type,"Zap"))
618 if (tmp->dataquality || clearchannel) x = 0;
619 ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
621 if (!strcmp(peer->type,"Zap"))
624 if (tmp->dataquality || clearchannel) x = 0;
625 ast_channel_setoption(peer,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
627 hanguptree(outgoing, peer);
629 /* If appropriate, log that we have a destination channel */
631 ast_cdr_setdestchan(chan->cdr, peer->name);
633 pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", peer->name);
635 pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", numsubst);
636 /* Make sure channels are compatible */
637 res = ast_channel_make_compatible(chan, peer);
639 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", chan->name, peer->name);
644 if( url && strlen(url) && ast_channel_supports_html(peer) ) {
645 ast_log(LOG_DEBUG, "app_dial: sendurl=%s.\n", url);
646 ast_channel_sendurl( peer, url );
651 ast_channel_setoption(chan,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
652 ast_channel_setoption(peer,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
654 res = ast_bridge_call(chan, peer, allowredir_in, allowredir_out, allowdisconnect | clearchannel);
658 ast_channel_setoption(chan,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
659 ast_channel_setoption(peer,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
662 if (res != AST_PBX_NO_HANGUP_PEER)
666 hanguptree(outgoing, NULL);
667 LOCAL_USER_REMOVE(u);
671 int unload_module(void)
673 STANDARD_HANGUP_LOCALUSERS;
674 return ast_unregister_application(app);
677 int load_module(void)
680 res = ast_register_application(app, dial_exec, synopsis, descrip);
684 char *description(void)
692 STANDARD_USECOUNT(res);
698 return ASTERISK_GPL_KEY;