cd26974fd23093cc7598a33c5fd59317d51501e0
[asterisk/asterisk.git] / apps / app_dial.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Trivial application to dial a channel and send an URL on answer
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
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>
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <sys/time.h>
33 #include <sys/signal.h>
34 #include <netinet/in.h>
35
36 #include <pthread.h>
37
38 static char *tdesc = "Dialing Application";
39
40 static char *app = "Dial";
41
42 static char *synopsis = "Place an call and connect to the current channel";
43
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"
57 "no-answer).\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 "      'H' -- allow caller to hang up by hitting *.\n"
67 "      'P[(x)]' -- privacy mode, using 'x' as database if provided.\n"
68 "  In addition to transferring the call, a call may be parked and then picked\n"
69 "up by another user.\n"
70 "  The optionnal URL will be sent to the called party if the channel supports\n"
71 "it.\n";
72
73 /* We define a customer "local user" structure because we
74    use it not only for keeping track of what is in use but
75    also for keeping track of who we're dialing. */
76
77 struct localuser {
78         struct ast_channel *chan;
79         int stillgoing;
80         int allowredirect;
81         int ringbackonly;
82         int musiconhold;
83         int dataquality;
84         int allowdisconnect;
85         struct localuser *next;
86 };
87
88 LOCAL_USER_DECL;
89
90 static void hanguptree(struct localuser *outgoing, struct ast_channel *exception)
91 {
92         /* Hang up a tree of stuff */
93         struct localuser *oo;
94         while(outgoing) {
95                 /* Hangup any existing lines we have open */
96                 if (outgoing->chan != exception)
97                         ast_hangup(outgoing->chan);
98                 oo = outgoing;
99                 outgoing=outgoing->next;
100                 free(oo);
101         }
102 }
103
104 #define MAX 256
105
106 static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localuser *outgoing, int *to, int *allowredir, int *allowdisconnect)
107 {
108         struct localuser *o;
109         int found;
110         int numlines;
111         int sentringing = 0;
112         int numbusies = 0;
113         int orig = *to;
114         struct ast_frame *f;
115         struct ast_channel *peer = NULL;
116         struct ast_channel *watchers[MAX];
117         int pos;
118         int single;
119         int moh=0;
120         int ringind=0;
121         struct ast_channel *winner;
122         
123         single = (outgoing && !outgoing->next && !outgoing->musiconhold && !outgoing->ringbackonly);
124         
125         if (single) {
126                 /* If we are calling a single channel, make them compatible for in-band tone purpose */
127                 ast_channel_make_compatible(outgoing->chan, in);
128         }
129         
130         if (outgoing) {
131                 moh = outgoing->musiconhold;
132                 ringind = outgoing->ringbackonly;
133                 if (outgoing->musiconhold) {
134                         ast_moh_start(in, NULL);
135                 } else if (outgoing->ringbackonly) {
136                         ast_indicate(in, AST_CONTROL_RINGING);
137                 }
138         }
139         
140         while(*to && !peer) {
141                 o = outgoing;
142                 found = -1;
143                 pos = 1;
144                 numlines = 0;
145                 watchers[0] = in;
146                 while(o) {
147                         /* Keep track of important channels */
148                         if (o->stillgoing) {
149                                 watchers[pos++] = o->chan;
150                                 found = 1;
151                         }
152                         o = o->next;
153                         numlines++;
154                 }
155                 if (found < 0) {
156                         if (numlines == numbusies) {
157                                 if (option_verbose > 2)
158                                         ast_verbose( VERBOSE_PREFIX_2 "Everyone is busy at this time\n");
159                                 /* See if there is a special busy message */
160                                 if (ast_exists_extension(in, in->context, in->exten, in->priority + 101, in->callerid)) 
161                                         in->priority+=100;
162                         } else {
163                                 if (option_verbose > 2)
164                                         ast_verbose( VERBOSE_PREFIX_2 "No one is available to answer at this time\n");
165                         }
166                         *to = 0;
167                         /* if no one available we'd better stop MOH/ringing to */
168                         if (moh) {
169                                 ast_moh_stop(in);
170                         } else if (ringind) {
171                                 ast_indicate(in, -1);
172                         }
173                         return NULL;
174                 }
175                 winner = ast_waitfor_n(watchers, pos, to);
176                 o = outgoing;
177                 while(o) {
178                         if (o->stillgoing && (o->chan->_state == AST_STATE_UP)) {
179                                 if (!peer) {
180                                         if (option_verbose > 2)
181                                                 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
182                                         peer = o->chan;
183                                         *allowredir = o->allowredirect;
184                                         *allowdisconnect = o->allowdisconnect;
185                                 }
186                         } else if (o->chan == winner) {
187                                 f = ast_read(winner);
188                                 if (f) {
189                                         if (f->frametype == AST_FRAME_CONTROL) {
190                                                 switch(f->subclass) {
191                                             case AST_CONTROL_ANSWER:
192                                                         /* This is our guy if someone answered. */
193                                                         if (!peer) {
194                                                                 if (option_verbose > 2)
195                                                                         ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
196                                                                 peer = o->chan;
197                                                                 *allowredir = o->allowredirect;
198                                                                 *allowdisconnect = o->allowdisconnect;
199                                                         }
200                                                         break;
201                                                 case AST_CONTROL_BUSY:
202                                                         if (option_verbose > 2)
203                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
204                                                         o->stillgoing = 0;
205                                                         if (in->cdr)
206                                                                 ast_cdr_busy(in->cdr);
207                                                         numbusies++;
208                                                         break;
209                                                 case AST_CONTROL_CONGESTION:
210                                                         if (option_verbose > 2)
211                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
212                                                         o->stillgoing = 0;
213                                                         if (in->cdr)
214                                                                 ast_cdr_busy(in->cdr);
215                                                         numbusies++;
216                                                         break;
217                                                 case AST_CONTROL_RINGING:
218                                                         if (option_verbose > 2)
219                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
220                                                         if (!sentringing) {
221                                                                 ast_indicate(in, AST_CONTROL_RINGING);
222                                                                 sentringing++;
223                                                                 ringind++;
224                                                         }
225                                                         break;
226                                                 case AST_CONTROL_OFFHOOK:
227                                                         /* Ignore going off hook */
228                                                         break;
229                                                 default:
230                                                         ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
231                                                 }
232                                         } else if (single && (f->frametype == AST_FRAME_VOICE) && 
233                                                                 !(outgoing->ringbackonly || outgoing->musiconhold)) {
234                                                 if (ast_write(in, f)) 
235                                                         ast_log(LOG_WARNING, "Unable to forward frame\n");
236                                         } else if (single && (f->frametype == AST_FRAME_IMAGE) && 
237                                                                 !(outgoing->ringbackonly || outgoing->musiconhold)) {
238                                                 if (ast_write(in, f))
239                                                         ast_log(LOG_WARNING, "Unable to forward image\n");
240                                         }
241                                         ast_frfree(f);
242                                 } else {
243                                         o->stillgoing = 0;
244                                 }
245                         }
246                         o = o->next;
247                 }
248                 if (winner == in) {
249                         f = ast_read(in);
250 #if 0
251                         if (f && (f->frametype != AST_FRAME_VOICE))
252                                         printf("Frame type: %d, %d\n", f->frametype, f->subclass);
253                         else if (!f || (f->frametype != AST_FRAME_VOICE))
254                                 printf("Hangup received on %s\n", in->name);
255 #endif
256                         if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
257                                 /* Got hung up */
258                                 *to=-1;
259                                 return NULL;
260                         }
261                         if (f && (f->frametype == AST_FRAME_DTMF) && allowdisconnect &&
262                                 (f->subclass == '*')) {
263                             if (option_verbose > 3)
264                                 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
265                                 *to=0;
266                                 return NULL;
267                         }
268                         if (single && ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_DTMF)))  {
269                                 if (ast_write(outgoing->chan, f))
270                                         ast_log(LOG_WARNING, "Unable to forward voice\n");
271                         }
272                 }
273                 if (!*to && (option_verbose > 2))
274                         ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
275         }
276         if (moh) {
277                 ast_moh_stop(in);
278         } else if (ringind) {
279                 ast_indicate(in, -1);
280         }
281
282         return peer;
283         
284 }
285
286 static int dial_exec(struct ast_channel *chan, void *data)
287 {
288         int res=-1;
289         struct localuser *u;
290         char info[256], *peers, *timeout, *tech, *number, *rest, *cur;
291         char  privdb[256] = "", *s;
292         struct localuser *outgoing=NULL, *tmp;
293         struct ast_channel *peer;
294         int to;
295         int allowredir=0;
296         int allowdisconnect=0;
297         int privacy=0;
298         char numsubst[AST_MAX_EXTENSION];
299         char restofit[AST_MAX_EXTENSION];
300         char *transfer = NULL;
301         char *newnum;
302         char callerid[256], *l, *n;
303         char *url=NULL; /* JDG */
304         struct ast_var_t *current;
305         struct varshead *headp, *newheadp;
306         struct ast_var_t *newvar;
307         
308         if (!data) {
309                 ast_log(LOG_WARNING, "Dial requires an argument (technology1/number1&technology2/number2...|optional timeout)\n");
310                 return -1;
311         }
312         
313         LOCAL_USER_ADD(u);
314         
315         /* Parse our arguments XXX Check for failure XXX */
316         strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
317         peers = info;
318         if (peers) {
319                 timeout = strchr(info, '|');
320                 if (timeout) {
321                         *timeout = '\0';
322                         timeout++;
323                         transfer = strchr(timeout, '|');
324                         if (transfer) {
325                                 *transfer = '\0';
326                                 transfer++;
327                                 /* JDG */
328                                 url = strchr(transfer, '|');
329                                 if (url) {
330                                         *url = '\0';
331                                         url++;
332                                         ast_log(LOG_DEBUG, "DIAL WITH URL=%s_\n", url);
333                                 } else 
334                                         ast_log(LOG_DEBUG, "SIMPLE DIAL (NO URL)\n");
335                                 /* /JDG */
336                         }
337                 }
338         } else
339                 timeout = NULL;
340         if (!peers || !strlen(peers)) {
341                 ast_log(LOG_WARNING, "Dial argument takes format (technology1/number1&technology2/number2...|optional timeout)\n");
342                 goto out;
343         }
344         
345
346         if (transfer) {
347                 /* Extract privacy info from transfer */
348                 if ((s = strstr(transfer, "P("))) {
349                         privacy = 1;
350                         strncpy(privdb, s + 2, sizeof(privdb) - 1);
351                         /* Overwrite with X's what was the privacy info */
352                         while(*s && (*s != ')')) 
353                                 *(s++) = 'X';
354                         if (*s)
355                                 *s = 'X';
356                         /* Now find the end of the privdb */
357                         s = strchr(privdb, ')');
358                         if (s)
359                                 *s = '\0';
360                         else {
361                                 ast_log(LOG_WARNING, "Transfer with privacy lacking trailing '('\n");
362                                 privacy = 0;
363                         }
364                 } else if (strchr(transfer, 'P')) {
365                         /* No specified privdb */
366                         privacy = 1;
367                 }
368         }
369         if (!strlen(privdb) && privacy) {
370                 /* If privdb is not specified and we are using privacy, copy from extension */
371                 strncpy(privdb, chan->exten, sizeof(privdb) - 1);
372         }
373         if (privacy) {
374                 if (chan->callerid)
375                         strncpy(callerid, chan->callerid, sizeof(callerid));
376                 else
377                         strcpy(callerid, "");
378                 ast_callerid_parse(callerid, &n, &l);
379                 if (l) {
380                         ast_shrink_phone_number(l);
381                 } else
382                         l = "";
383                 ast_log(LOG_NOTICE, "Privacy DB is '%s', privacy is %d, clid is '%s'\n", privdb, privacy, l);
384         }
385         cur = peers;
386         do {
387                 /* Remember where to start next time */
388                 rest = strchr(cur, '&');
389                 if (rest) {
390                         *rest = 0;
391                         rest++;
392                 }
393                 /* Get a technology/[device:]number pair */
394                 tech = cur;
395                 number = strchr(tech, '/');
396                 if (!number) {
397                         ast_log(LOG_WARNING, "Dial argument takes format (technology1/[device:]number1&technology2/[device:]number2...|optional timeout)\n");
398                         goto out;
399                 }
400                 *number = '\0';
401                 number++;
402                 tmp = malloc(sizeof(struct localuser));
403                 if (!tmp) {
404                         ast_log(LOG_WARNING, "Out of memory\n");
405                         goto out;
406                 }
407                 memset(tmp, 0, sizeof(struct localuser));
408                 if (transfer) {
409                         if (strchr(transfer, 't'))
410                                 tmp->allowredirect = 1;
411                         else    tmp->allowredirect = 0;
412                         if (strchr(transfer, 'r'))
413                                 tmp->ringbackonly = 1;
414                         else    tmp->ringbackonly = 0;
415                         if (strchr(transfer, 'm'))
416                                 tmp->musiconhold = 1;
417                         else    tmp->musiconhold = 0;
418                         if (strchr(transfer, 'd'))
419                                 tmp->dataquality = 1;
420                         else    tmp->dataquality = 0;
421                         if (strchr(transfer, 'H'))
422                                 tmp->allowdisconnect = 1;
423                         else    tmp->allowdisconnect = 0;
424                 }
425                 strncpy(numsubst, number, sizeof(numsubst)-1);
426                 /* If we're dialing by extension, look at the extension to know what to dial */
427                 if ((newnum = strstr(numsubst, "BYEXTENSION"))) {
428                         strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit)-1);
429                         snprintf(newnum, sizeof(numsubst) - (newnum - numsubst), "%s%s", chan->exten,restofit);
430                         if (option_debug)
431                                 ast_log(LOG_DEBUG, "Dialing by extension %s\n", numsubst);
432                 }
433                 /* Request the peer */
434                 tmp->chan = ast_request(tech, chan->nativeformats, numsubst);
435                 if (!tmp->chan) {
436                         /* If we can't, just go on to the next call */
437                         ast_log(LOG_NOTICE, "Unable to create channel of type '%s'\n", tech);
438                         if (chan->cdr)
439                                 ast_cdr_busy(chan->cdr);
440                         free(tmp);
441                         cur = rest;
442                         continue;
443                 }
444                 if (strlen(tmp->chan->call_forward)) {
445                         if (option_verbose > 2)
446                                 ast_verbose(VERBOSE_PREFIX_3 "Forwarding call to '%s@%s'\n", tmp->chan->call_forward, tmp->chan->context);
447                         /* Setup parameters */
448                         strncpy(chan->exten, tmp->chan->call_forward, sizeof(chan->exten));
449                         strncpy(chan->context, tmp->chan->context, sizeof(chan->context));
450                         chan->priority = 0;
451                         to = 0;
452                         ast_hangup(tmp->chan);
453                         free(tmp);
454                         cur = rest;
455                         break;
456                 }
457                 /* If creating a SIP channel, look for a variable called */
458                 /* VXML_URL in the calling channel and copy it to the    */
459                 /* new channel.                                          */
460                 if (strcasecmp(tech,"SIP")==0)
461                 {
462                         headp=&chan->varshead;
463                         AST_LIST_TRAVERSE(headp,current,entries) {
464                                 if (strcasecmp(ast_var_name(current),"VXML_URL")==0)
465                                 {
466                                         newvar=ast_var_assign(ast_var_name(current),ast_var_value(current));
467                                         newheadp=&tmp->chan->varshead;
468                                         AST_LIST_INSERT_HEAD(newheadp,newvar,entries);
469                                         break;
470                                 }
471                         }
472                 }
473                 
474                 tmp->chan->appl = "AppDial";
475                 tmp->chan->data = "(Outgoing Line)";
476                 tmp->chan->whentohangup = 0;
477                 if (tmp->chan->callerid)
478                         free(tmp->chan->callerid);
479                 if (tmp->chan->ani)
480                         free(tmp->chan->ani);
481                 if (chan->callerid)
482                         tmp->chan->callerid = strdup(chan->callerid);
483                 else
484                         tmp->chan->callerid = NULL;
485                 if (chan->ani)
486                         tmp->chan->ani = strdup(chan->ani);
487                 else
488                         tmp->chan->ani = NULL;
489                 /* Presense of ADSI CPE on outgoing channel follows ours */
490                 tmp->chan->adsicpe = chan->adsicpe;
491                 /* Place the call, but don't wait on the answer */
492                 res = ast_call(tmp->chan, numsubst, 0);
493                 if (res) {
494                         /* Again, keep going even if there's an error */
495                         if (option_debug)
496                                 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
497                         else if (option_verbose > 2)
498                                 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", numsubst);
499                         ast_hangup(tmp->chan);
500                         free(tmp);
501                         cur = rest;
502                         continue;
503                 } else
504                         if (option_verbose > 2)
505                                 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", numsubst);
506                 /* Put them in the list of outgoing thingies...  We're ready now. 
507                    XXX If we're forcibly removed, these outgoing calls won't get
508                    hung up XXX */
509                 tmp->stillgoing = -1;
510                 tmp->next = outgoing;
511                 outgoing = tmp;
512                 /* If this line is up, don't try anybody else */
513                 if (outgoing->chan->_state == AST_STATE_UP)
514                         break;
515                 cur = rest;
516         } while(cur);
517         
518         if (timeout && strlen(timeout))
519                 to = atoi(timeout) * 1000;
520         else
521                 to = -1;
522         peer = wait_for_answer(chan, outgoing, &to, &allowredir, &allowdisconnect);
523         if (!peer) {
524                 if (to) 
525                         /* Musta gotten hung up */
526                         res = -1;
527                  else 
528                         /* Nobody answered, next please? */
529                         res=0;
530                 
531                 goto out;
532         }
533         if (peer) {
534                 /* Ah ha!  Someone answered within the desired timeframe.  Of course after this
535                    we will always return with -1 so that it is hung up properly after the 
536                    conversation.  */
537                 if (!strcmp(chan->type,"Zap"))
538                 {
539                         int x = 2;
540                         if (tmp->dataquality) x = 0;
541                         ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
542                 }                       
543                 if (!strcmp(peer->type,"Zap"))
544                 {
545                         int x = 2;
546                         if (tmp->dataquality) x = 0;
547                         ast_channel_setoption(peer,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
548                 }                       
549                 hanguptree(outgoing, peer);
550                 outgoing = NULL;
551                 /* If appropriate, log that we have a destination channel */
552                 if (chan->cdr)
553                         ast_cdr_setdestchan(chan->cdr, peer->name);
554                 /* Make sure channels are compatible */
555                 res = ast_channel_make_compatible(chan, peer);
556                 if (res < 0) {
557                         ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", chan->name, peer->name);
558                         ast_hangup(peer);
559                         return -1;
560                 }
561                 /* JDG: sendurl */
562                 if( url && strlen(url) && ast_channel_supports_html(peer) ) {
563                         ast_log(LOG_DEBUG, "app_dial: sendurl=%s.\n", url);
564                         ast_channel_sendurl( peer, url );
565                 } /* /JDG */
566                 res = ast_bridge_call(chan, peer, allowredir, allowdisconnect);
567                 ast_hangup(peer);
568         }       
569 out:
570         hanguptree(outgoing, NULL);
571         LOCAL_USER_REMOVE(u);
572         return res;
573 }
574
575 int unload_module(void)
576 {
577         STANDARD_HANGUP_LOCALUSERS;
578         return ast_unregister_application(app);
579 }
580
581 int load_module(void)
582 {
583         int res;
584         res = ast_register_application(app, dial_exec, synopsis, descrip);
585         return res;
586 }
587
588 char *description(void)
589 {
590         return tdesc;
591 }
592
593 int usecount(void)
594 {
595         int res;
596         STANDARD_USECOUNT(res);
597         return res;
598 }
599
600 char *key()
601 {
602         return ASTERISK_GPL_KEY;
603 }