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