Version 0.2.0 from FTP
[asterisk/asterisk.git] / apps / app_dial.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Trivial application to dial a channel
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 <stdlib.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <sys/time.h>
32 #include <sys/signal.h>
33 #include <netinet/in.h>
34
35 #include <pthread.h>
36
37 static char *tdesc = "Dialing Application";
38
39 static char *app = "Dial";
40
41 static char *synopsis = "Place an call and connect to the current channel";
42
43 static char *descrip =
44 "  Dial(Technology/resource[&Technology2/resource2...][|timeout][|options]):\n"
45 "Requests  one  or more channels and places specified outgoing calls on them.\n"
46 "As soon as a  channel  answers, the  Dial  app  will  answer the originating\n"
47 "channel (if it needs to be answered) and will bridge a call with the channel\n"
48 "which first answered. All other calls placed by the Dial app will be hunp up\n"
49 "If a timeout is not specified, the Dial  application  will wait indefinitely\n"
50 "until either one of the  called channels  answers, the user hangs up, or all\n"
51 "channels return busy or  error. In general,  the dialler will return 0 if it\n"
52 "was  unable  to  place  the  call, or the timeout expired.  However, if  all\n"
53 "channels were busy, and there exists an extension with priority n+101 (where\n"
54 "n is the priority of  the  dialler  instance), then  it  will  be  the  next\n"
55 "executed extension (this allows you to setup different behavior on busy from\n"
56 "no-answer).\n"
57 "  This application returns -1 if the originating channel hangs up, or if the\n"
58 "call is bridged and  either of the parties in the bridge terminate the call.\n"
59 "The option string may contain zero or more of the following characters:\n"
60 "      't' -- allow the called user transfer the calling user\n"
61 "      'T' -- to allow the calling user to transfer the call.\n"
62 "      'r' -- indicate ringing to the calling party, pass no audio until answered.\n"
63 "      'm' -- provide hold music to the calling party until answered.\n"
64 "      'd' -- data-quality (modem) call (minimum delay).\n"
65 "      'H' -- allow caller to hang up by hitting *.\n"
66 "  In addition to transferring the call, a call may be parked and then picked\n"
67 "up by another user.\n";
68
69 /* We define a customer "local user" structure because we
70    use it not only for keeping track of what is in use but
71    also for keeping track of who we're dialing. */
72
73 struct localuser {
74         struct ast_channel *chan;
75         int stillgoing;
76         int allowredirect;
77         int ringbackonly;
78         int musiconhold;
79         int dataquality;
80         int allowdisconnect;
81         struct localuser *next;
82 };
83
84 LOCAL_USER_DECL;
85
86 static void hanguptree(struct localuser *outgoing, struct ast_channel *exception)
87 {
88         /* Hang up a tree of stuff */
89         struct localuser *oo;
90         while(outgoing) {
91                 /* Hangup any existing lines we have open */
92                 if (outgoing->chan != exception)
93                         ast_hangup(outgoing->chan);
94                 oo = outgoing;
95                 outgoing=outgoing->next;
96                 free(oo);
97         }
98 }
99
100 #define MAX 256
101
102 static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localuser *outgoing, int *to, int *allowredir, int *allowdisconnect)
103 {
104         struct localuser *o;
105         int found;
106         int numlines;
107         int sentringing = 0;
108         int numbusies = 0;
109         int orig = *to;
110         struct ast_frame *f;
111         struct ast_channel *peer = NULL;
112         struct ast_channel *watchers[MAX];
113         int pos;
114         int single;
115         int moh=0;
116         int ringind=0;
117         struct ast_channel *winner;
118         
119         single = (outgoing && !outgoing->next);
120         
121         if (single) {
122                 /* If we are calling a single channel, make them compatible for in-band tone purpose */
123                 ast_channel_make_compatible(outgoing->chan, in);
124         }
125         
126         if (outgoing) {
127                 moh = outgoing->musiconhold;
128                 ringind = outgoing->ringbackonly;
129                 if (outgoing->musiconhold) {
130                         ast_moh_start(in, NULL);
131                 } else if (outgoing->ringbackonly) {
132                         ast_indicate(in, AST_CONTROL_RINGING);
133                 }
134         }
135         
136         while(*to && !peer) {
137                 o = outgoing;
138                 found = -1;
139                 pos = 1;
140                 numlines = 0;
141                 watchers[0] = in;
142                 while(o) {
143                         /* Keep track of important channels */
144                         if (o->stillgoing) {
145                                 watchers[pos++] = o->chan;
146                                 found = 1;
147                         }
148                         o = o->next;
149                         numlines++;
150                 }
151                 if (found < 0) {
152                         if (numlines == numbusies) {
153                                 if (option_verbose > 2)
154                                         ast_verbose( VERBOSE_PREFIX_2 "Everyone is busy at this time\n");
155                                 /* See if there is a special busy message */
156                                 if (ast_exists_extension(in, in->context, in->exten, in->priority + 101, in->callerid)) 
157                                         in->priority+=100;
158                         } else {
159                                 if (option_verbose > 2)
160                                         ast_verbose( VERBOSE_PREFIX_2 "No one is available to answer at this time\n");
161                         }
162                         *to = 0;
163                         return NULL;
164                 }
165                 winner = ast_waitfor_n(watchers, pos, to);
166                 o = outgoing;
167                 while(o) {
168                         if (o->stillgoing && (o->chan->_state == AST_STATE_UP)) {
169                                 if (!peer) {
170                                         if (option_verbose > 2)
171                                                 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
172                                         peer = o->chan;
173                                         *allowredir = o->allowredirect;
174                                         *allowdisconnect = o->allowdisconnect;
175                                 }
176                         } else if (o->chan == winner) {
177                                 f = ast_read(winner);
178                                 if (f) {
179                                         if (f->frametype == AST_FRAME_CONTROL) {
180                                                 switch(f->subclass) {
181                                             case AST_CONTROL_ANSWER:
182                                                         /* This is our guy if someone answered. */
183                                                         if (!peer) {
184                                                                 if (option_verbose > 2)
185                                                                         ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
186                                                                 peer = o->chan;
187                                                                 *allowredir = o->allowredirect;
188                                                                 *allowdisconnect = o->allowdisconnect;
189                                                         }
190                                                         break;
191                                                 case AST_CONTROL_BUSY:
192                                                         if (option_verbose > 2)
193                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
194                                                         o->stillgoing = 0;
195                                                         if (in->cdr)
196                                                                 ast_cdr_busy(in->cdr);
197                                                         numbusies++;
198                                                         break;
199                                                 case AST_CONTROL_CONGESTION:
200                                                         if (option_verbose > 2)
201                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
202                                                         o->stillgoing = 0;
203                                                         if (in->cdr)
204                                                                 ast_cdr_busy(in->cdr);
205                                                         numbusies++;
206                                                         break;
207                                                 case AST_CONTROL_RINGING:
208                                                         if (option_verbose > 2)
209                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
210                                                         if (!sentringing) {
211                                                                 ast_indicate(in, AST_CONTROL_RINGING);
212                                                                 sentringing++;
213                                                         }
214                                                         break;
215                                                 case AST_CONTROL_OFFHOOK:
216                                                         /* Ignore going off hook */
217                                                         break;
218                                                 default:
219                                                         ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
220                                                 }
221                                         } else if (single && (f->frametype == AST_FRAME_VOICE) && 
222                                                                 !(outgoing->ringbackonly || outgoing->musiconhold)) {
223                                                 if (ast_write(in, f)) 
224                                                         ast_log(LOG_WARNING, "Unable to forward frame\n");
225                                         } else if (single && (f->frametype == AST_FRAME_IMAGE) && 
226                                                                 !(outgoing->ringbackonly || outgoing->musiconhold)) {
227                                                 if (ast_write(in, f))
228                                                         ast_log(LOG_WARNING, "Unable to forward image\n");
229                                         }
230                                         ast_frfree(f);
231                                 } else {
232                                         o->stillgoing = 0;
233                                 }
234                         }
235                         o = o->next;
236                 }
237                 if (winner == in) {
238                         f = ast_read(in);
239 #if 0
240                         if (f && (f->frametype != AST_FRAME_VOICE))
241                                         printf("Frame type: %d, %d\n", f->frametype, f->subclass);
242                         else if (!f || (f->frametype != AST_FRAME_VOICE))
243                                 printf("Hangup received on %s\n", in->name);
244 #endif
245                         if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
246                                 /* Got hung up */
247                                 *to=-1;
248                                 return NULL;
249                         }
250                         if (f && (f->frametype == AST_FRAME_DTMF) && allowdisconnect &&
251                                 (f->subclass == '*')) {
252                             if (option_verbose > 3)
253                                 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
254                                 *to=0;
255                                 return NULL;
256                         }
257                         if (single && ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_DTMF)))  {
258                                 if (ast_write(outgoing->chan, f))
259                                         ast_log(LOG_WARNING, "Unable to forward voice\n");
260                         }
261                 }
262                 if (!*to && (option_verbose > 2))
263                         ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
264         }
265         if (moh) {
266                 ast_moh_stop(in);
267         } else if (ringind) {
268                 ast_indicate(in, -1);
269         }
270
271         return peer;
272         
273 }
274
275 static int dial_exec(struct ast_channel *chan, void *data)
276 {
277         int res=-1;
278         struct localuser *u;
279         char info[256], *peers, *timeout, *tech, *number, *rest, *cur;
280         struct localuser *outgoing=NULL, *tmp;
281         struct ast_channel *peer;
282         int to;
283         int allowredir=0;
284         int allowdisconnect=0;
285         char numsubst[AST_MAX_EXTENSION];
286         char restofit[AST_MAX_EXTENSION];
287         char *transfer = NULL;
288         char *newnum;
289         
290         if (!data) {
291                 ast_log(LOG_WARNING, "Dial requires an argument (technology1/number1&technology2/number2...|optional timeout)\n");
292                 return -1;
293         }
294         
295         LOCAL_USER_ADD(u);
296         
297         /* Parse our arguments XXX Check for failure XXX */
298         strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
299         peers = info;
300         if (peers) {
301                 timeout = strchr(info, '|');
302                 if (timeout) {
303                         *timeout = '\0';
304                         timeout++;
305                         transfer = strchr(timeout, '|');
306                         if (transfer) {
307                                 *transfer = '\0';
308                                 transfer++;
309                         }
310                 }
311         } else
312                 timeout = NULL;
313         if (!peers || !strlen(peers)) {
314                 ast_log(LOG_WARNING, "Dial argument takes format (technology1/number1&technology2/number2...|optional timeout)\n");
315                 goto out;
316         }
317         
318         cur = peers;
319         do {
320                 /* Remember where to start next time */
321                 rest = strchr(cur, '&');
322                 if (rest) {
323                         *rest = 0;
324                         rest++;
325                 }
326                 /* Get a technology/[device:]number pair */
327                 tech = cur;
328                 number = strchr(tech, '/');
329                 if (!number) {
330                         ast_log(LOG_WARNING, "Dial argument takes format (technology1/[device:]number1&technology2/[device:]number2...|optional timeout)\n");
331                         goto out;
332                 }
333                 *number = '\0';
334                 number++;
335                 tmp = malloc(sizeof(struct localuser));
336                 if (!tmp) {
337                         ast_log(LOG_WARNING, "Out of memory\n");
338                         goto out;
339                 }
340                 memset(tmp, 0, sizeof(struct localuser));
341                 if (transfer) {
342                         if (strchr(transfer, 't'))
343                                 tmp->allowredirect = 1;
344                         if (strchr(transfer, 'r'))
345                                 tmp->ringbackonly = 1;
346                         if (strchr(transfer, 'm'))
347                                 tmp->musiconhold = 1;
348                         if (strchr(transfer, 'd'))
349                                 tmp->dataquality = 1;
350                         if (strchr(transfer, 'H'))
351                                 tmp->allowdisconnect = 1;
352                 }
353                 strncpy(numsubst, number, sizeof(numsubst)-1);
354                 /* If we're dialing by extension, look at the extension to know what to dial */
355                 if ((newnum = strstr(numsubst, "BYEXTENSION"))) {
356                         strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit)-1);
357                         snprintf(newnum, sizeof(numsubst) - (newnum - numsubst), "%s%s", chan->exten,restofit);
358                         if (option_debug)
359                                 ast_log(LOG_DEBUG, "Dialing by extension %s\n", numsubst);
360                 }
361                 /* Request the peer */
362                 tmp->chan = ast_request(tech, chan->nativeformats, numsubst);
363                 if (!tmp->chan) {
364                         /* If we can't, just go on to the next call */
365                         ast_log(LOG_NOTICE, "Unable to create channel of type '%s'\n", tech);
366                         if (chan->cdr)
367                                 ast_cdr_busy(chan->cdr);
368                         free(tmp);
369                         cur = rest;
370                         continue;
371                 }
372                 if (strlen(tmp->chan->call_forward)) {
373                         if (option_verbose > 2)
374                                 ast_verbose(VERBOSE_PREFIX_3 "Forwarding call to '%s@%s'\n", tmp->chan->call_forward, tmp->chan->context);
375                         /* Setup parameters */
376                         strncpy(chan->exten, tmp->chan->call_forward, sizeof(chan->exten));
377                         strncpy(chan->context, tmp->chan->context, sizeof(chan->context));
378                         chan->priority = 0;
379                         to = 0;
380                         ast_hangup(tmp->chan);
381                         free(tmp);
382                         cur = rest;
383                         break;
384                 }
385                 tmp->chan->appl = "AppDial";
386                 tmp->chan->data = "(Outgoing Line)";
387                 tmp->chan->whentohangup = 0;
388                 if (tmp->chan->callerid)
389                         free(tmp->chan->callerid);
390                 if (tmp->chan->ani)
391                         free(tmp->chan->ani);
392                 if (chan->callerid)
393                         tmp->chan->callerid = strdup(chan->callerid);
394                 else
395                         tmp->chan->callerid = NULL;
396                 if (chan->ani)
397                         tmp->chan->ani = strdup(chan->ani);
398                 else
399                         tmp->chan->ani = NULL;
400                 /* Presense of ADSI CPE on outgoing channel follows ours */
401                 tmp->chan->adsicpe = chan->adsicpe;
402                 /* Place the call, but don't wait on the answer */
403                 res = ast_call(tmp->chan, numsubst, 0);
404                 if (res) {
405                         /* Again, keep going even if there's an error */
406                         if (option_debug)
407                                 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
408                         else if (option_verbose > 2)
409                                 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", numsubst);
410                         ast_hangup(tmp->chan);
411                         free(tmp);
412                         cur = rest;
413                         continue;
414                 } else
415                         if (option_verbose > 2)
416                                 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", numsubst);
417                 /* Put them in the list of outgoing thingies...  We're ready now. 
418                    XXX If we're forcibly removed, these outgoing calls won't get
419                    hung up XXX */
420                 tmp->stillgoing = -1;
421                 tmp->next = outgoing;
422                 outgoing = tmp;
423                 /* If this line is up, don't try anybody else */
424                 if (outgoing->chan->_state == AST_STATE_UP)
425                         break;
426                 cur = rest;
427         } while(cur);
428         
429         if (timeout && strlen(timeout))
430                 to = atoi(timeout) * 1000;
431         else
432                 to = -1;
433         peer = wait_for_answer(chan, outgoing, &to, &allowredir, &allowdisconnect);
434         if (!peer) {
435                 if (to) 
436                         /* Musta gotten hung up */
437                         res = -1;
438                  else 
439                         /* Nobody answered, next please? */
440                         res=0;
441                 
442                 goto out;
443         }
444         if (peer) {
445                 /* Ah ha!  Someone answered within the desired timeframe.  Of course after this
446                    we will always return with -1 so that it is hung up properly after the 
447                    conversation.  */
448                 hanguptree(outgoing, peer);
449                 outgoing = NULL;
450                 /* If appropriate, log that we have a destination channel */
451                 if (chan->cdr)
452                         ast_cdr_setdestchan(chan->cdr, peer->name);
453                 /* Make sure channels are compatible */
454                 res = ast_channel_make_compatible(chan, peer);
455                 if (res < 0) {
456                         ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", chan->name, peer->name);
457                         ast_hangup(peer);
458                         return -1;
459                 }
460                 if (!strcmp(chan->type,"Zap")) {
461                         int x = 2;
462                         if (tmp->dataquality) x = 0;
463                         ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
464                 }                       
465                 if (!strcmp(peer->type,"Zap")) {
466                         int x = 2;
467                         if (tmp->dataquality) x = 0;
468                         ast_channel_setoption(peer,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
469                 }                       
470                 res = ast_bridge_call(chan, peer, allowredir, allowdisconnect);
471                 ast_hangup(peer);
472         }       
473 out:
474         hanguptree(outgoing, NULL);
475         LOCAL_USER_REMOVE(u);
476         return res;
477 }
478
479 int unload_module(void)
480 {
481         STANDARD_HANGUP_LOCALUSERS;
482         return ast_unregister_application(app);
483 }
484
485 int load_module(void)
486 {
487         int res;
488         res = ast_register_application(app, dial_exec, synopsis, descrip);
489         return res;
490 }
491
492 char *description(void)
493 {
494         return tdesc;
495 }
496
497 int usecount(void)
498 {
499         int res;
500         STANDARD_USECOUNT(res);
501         return res;
502 }
503
504 char *key()
505 {
506         return ASTERISK_GPL_KEY;
507 }