2 * Asterisk -- A telephony toolkit for Linux.
4 * Trivial application to dial a channel
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/file.h>
15 #include <asterisk/logger.h>
16 #include <asterisk/channel.h>
17 #include <asterisk/pbx.h>
18 #include <asterisk/options.h>
19 #include <asterisk/module.h>
20 #include <asterisk/translate.h>
21 #include <asterisk/say.h>
29 #include <sys/signal.h>
33 static char *tdesc = "Dialing/Parking Application";
35 static char *app = "Dial";
37 static char *parkedcall = "ParkedCall";
39 /* No more than 90 seconds parked before you do something with them */
40 static int parkingtime = 90000;
42 /* Context for which parking is made accessible */
43 static char parking_con[AST_MAX_EXTENSION] = "default";
45 /* Extension you type to park the call */
46 static char parking_ext[AST_MAX_EXTENSION] = "700";
48 /* First available extension for parking */
49 static int parking_start = 701;
51 /* Last available extension for parking */
52 static int parking_stop = 750;
54 /* We define a customer "local user" structure because we
55 use it not only for keeping track of what is in use but
56 also for keeping track of who we're dialing. */
59 struct ast_channel *chan;
62 struct localuser *next;
66 struct ast_channel *chan;
69 /* Where to go if our parking time expires */
70 char context[AST_MAX_EXTENSION];
71 char exten[AST_MAX_EXTENSION];
73 struct parkeduser *next;
76 static struct parkeduser *parkinglot;
78 static pthread_mutex_t parking_lock = PTHREAD_MUTEX_INITIALIZER;
80 static pthread_t parking_thread;
84 static int bridge_call(struct ast_channel *chan, struct ast_channel *peer, int allowredirect);
87 static int park_call(struct ast_channel *chan, struct ast_channel *peer)
89 /* We put the user in the parking list, then wake up the parking thread to be sure it looks
90 after these channels too */
91 struct parkeduser *pu, *cur;
93 pu = malloc(sizeof(struct parkeduser));
95 pthread_mutex_lock(&parking_lock);
96 for (x=parking_start;x<=parking_stop;x++) {
99 if (cur->parkingnum == x)
106 if (x <= parking_stop) {
108 gettimeofday(&pu->start, NULL);
110 /* Remember what had been dialed, so that if the parking
111 expires, we try to come back to the same place */
112 strncpy(pu->context, chan->context, sizeof(pu->context));
113 strncpy(pu->exten, chan->exten, sizeof(pu->exten));
114 pu->priority = chan->priority;
115 pu->next = parkinglot;
117 pthread_mutex_unlock(&parking_lock);
118 /* Wake up the (presumably select()ing) thread */
119 pthread_kill(parking_thread, SIGURG);
120 if (option_verbose > 1)
121 ast_verbose(VERBOSE_PREFIX_2 "Parked %s on %d\n", pu->chan->name, pu->parkingnum);
122 ast_say_digits(peer, pu->parkingnum, peer->language);
125 ast_log(LOG_WARNING, "No more parking spaces\n");
127 pthread_mutex_unlock(&parking_lock);
131 ast_log(LOG_WARNING, "Out of memory\n");
137 static void *do_parking_thread(void *ignore)
140 struct parkeduser *pu, *pl, *pt = NULL;
150 pthread_mutex_lock(&parking_lock);
153 gettimeofday(&tv, NULL);
157 tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000;
158 if (tms > parkingtime) {
159 /* They've been waiting too long, send them back to where they came. Theoretically they
160 should have their original extensions and such, but we copy to be on the safe side */
161 strncpy(pu->chan->exten, pu->exten, sizeof(pu->chan->exten));
162 strncpy(pu->chan->context, pu->context, sizeof(pu->chan->context));
163 pu->chan->priority = pu->priority;
164 /* Start up the PBX, or hang them up */
165 if (ast_pbx_start(pu->chan)) {
166 ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
167 ast_hangup(pu->chan);
169 /* And take them out of the parking lot */
173 parkinglot = pu->next;
177 } else if (FD_ISSET(pu->chan->fd, &rfds) || FD_ISSET(pu->chan->fd, &efds)) {
178 /* See if they need servicing */
179 f = ast_read(pu->chan);
180 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
181 /* There's a problem, hang them up*/
182 if (option_verbose > 1)
183 ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", pu->chan->name);
184 ast_hangup(pu->chan);
185 /* And take them out of the parking lot */
189 parkinglot = pu->next;
194 /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
196 goto std; /* XXX Ick: jumping into an else statement??? XXX */
199 /* Keep this one for next one */
200 std: FD_SET(pu->chan->fd, &nrfds);
201 FD_SET(pu->chan->fd, &nefds);
202 /* Keep track of our longest wait */
203 if ((tms < ms) || (ms < 0))
205 if (pu->chan->fd > max)
211 pthread_mutex_unlock(&parking_lock);
214 tv.tv_sec = ms / 1000;
215 tv.tv_usec = (ms % 1000) * 1000;
216 /* Wait for something to happen */
217 select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
218 pthread_testcancel();
220 return NULL; /* Never reached */
223 static void hanguptree(struct localuser *outgoing, struct ast_channel *exception)
225 /* Hang up a tree of stuff */
226 struct localuser *oo;
228 /* Hangup any existing lines we have open */
229 if (outgoing->chan != exception)
230 ast_hangup(outgoing->chan);
232 outgoing=outgoing->next;
237 static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localuser *outgoing, int *to, int *allowredir)
247 struct ast_channel *peer = NULL;
248 /* Watch all outgoing channels looking for an answer of some sort. */
249 tv.tv_sec = *to / 1000;
250 tv.tv_usec = (*to % 1000) * 1000;
251 while((tv.tv_sec || tv.tv_usec) && !peer) {
254 /* Always watch the input fd */
255 FD_SET(in->fd, &rfds);
256 FD_SET(in->fd, &efds);
262 /* Pay attention to this one */
263 CHECK_BLOCKING(o->chan);
264 FD_SET(o->chan->fd, &rfds);
265 FD_SET(o->chan->fd, &efds);
266 if (o->chan->fd > found)
272 /* If nobody is left, just go ahead and stop */
274 if (numlines == numbusies) {
275 if (option_verbose > 2)
276 ast_verbose( VERBOSE_PREFIX_2 "Everyone is busy at this time\n");
277 /* See if there is a special busy message */
278 if (ast_exists_extension(in, in->context, in->exten, in->priority + 101))
281 if (option_verbose > 2)
282 ast_verbose( VERBOSE_PREFIX_2 "No one is available to answer at this time\n");
289 found = select(found + 1, &rfds, NULL, &efds, &tv);
291 found = select(found + 1, &rfds, NULL, &efds, NULL);
293 ast_log(LOG_WARNING, "select failed, returned %d (%s)\n", errno, strerror(errno));
298 o->chan->blocking = 0;
307 o->chan->blocking = 0;
308 if (FD_ISSET(o->chan->fd, &rfds) || FD_ISSET(o->chan->fd, &efds)) {
309 f = ast_read(o->chan);
311 if (f->frametype == AST_FRAME_CONTROL) {
312 switch(f->subclass) {
313 case AST_CONTROL_ANSWER:
314 /* This is our guy if someone answered. */
316 if (option_verbose > 2)
317 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
319 *allowredir = o->allowredirect;
322 case AST_CONTROL_BUSY:
323 if (option_verbose > 2)
324 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
328 case AST_CONTROL_RINGING:
329 if (option_verbose > 2)
330 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
332 case AST_CONTROL_OFFHOOK:
333 /* Ignore going off hook */
336 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
348 if (FD_ISSET(in->fd, &rfds) || FD_ISSET(in->fd, &efds)) {
349 /* After unblocking the entirity of the list, check for the main channel */
352 if (f && (f->frametype != AST_FRAME_VOICE))
353 printf("Frame type: %d, %d\n", f->frametype, f->subclass);
355 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass = AST_CONTROL_HANGUP))) {
363 if (!(tv.tv_sec || tv.tv_usec) && (option_verbose > 2))
364 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
369 static int bridge_call(struct ast_channel *chan, struct ast_channel *peer, int allowredirect)
371 /* Copy voice back and forth between the two channels. Give the peer
372 the ability to transfer calls with '#<extension' syntax. */
373 struct ast_channel *cs[3];
376 struct ast_channel *who;
377 char newext[256], *ptr;
379 /* Answer if need be */
380 if (chan->state != AST_STATE_UP)
381 if (ast_answer(chan))
383 peer->appl = "Bridged Call";
384 peer->data = chan->name;
388 who = ast_waitfor_n(cs, 2, &to);
390 ast_log(LOG_WARNING, "Nobody there??\n");
394 if (!f || ((f->frametype == AST_FRAME_CONTROL) &&
395 ((f->subclass == AST_CONTROL_HANGUP) ||
396 (f->subclass == AST_CONTROL_BUSY))))
398 if ((f->frametype == AST_FRAME_VOICE) ||
399 (f->frametype == AST_FRAME_DTMF) ||
400 (f->frametype == AST_FRAME_TEXT)) {
401 if ((f->frametype == AST_FRAME_DTMF) && (who == peer) && allowredirect &&
402 (f->subclass == '#')) {
403 if (f->subclass == '#') {
404 memset(newext, 0, sizeof(newext));
406 len = ast_pbx_longest_extension(chan->context) + 1;
407 if (len < ast_pbx_longest_extension("default") + 1)
408 len = ast_pbx_longest_extension("default") + 1;
411 if ((res=ast_streamfile(peer, "pbx-transfer", chan->language)))
413 if ((res=ast_waitstream(peer, AST_DIGIT_ANY)) < 0)
415 ast_stopstream(peer);
417 /* If they've typed a digit already, handle it */
422 res = ast_readstring(peer, ptr, len, 3000, 2000, "#");
425 if (!strcmp(newext, parking_ext)) {
426 if (!park_call(chan, peer)) {
427 /* We return non-zero, but tell the PBX not to hang the channel when
428 the thread dies -- We have to be careful now though. We are responsible for
429 hanging up the channel, else it will never be hung up! */
430 res=AST_PBX_KEEPALIVE;
433 ast_log(LOG_WARNING, "Unable to park call %s\n", chan->name);
435 /* XXX Maybe we should have another message here instead of invalid extension XXX */
436 } else if (ast_exists_extension(chan, peer->context, newext, 1)) {
437 /* Set the channel's new extension, since it exists, using peer context */
438 strncpy(chan->exten, newext, sizeof(chan->exten));
439 strncpy(chan->context, peer->context, sizeof(chan->context));
444 } else if (ast_exists_extension(chan, "default", newext, 1)) {
445 /* Set the channel's new extension, since it exists, using peer context */
446 strncpy(chan->exten, newext, sizeof(chan->exten));
447 strncpy(chan->context, "default", sizeof(chan->context));
453 res = ast_streamfile(peer, "pbx-invalid", chan->language);
456 res = ast_waitstream(peer, AST_DIGIT_ANY);
457 ast_stopstream(peer);
462 ast_log(LOG_DEBUG, "Read from %s\n", who->name);
473 /* Swap who gets priority */
481 static int park_exec(struct ast_channel *chan, void *data)
485 struct ast_channel *peer=NULL, *nchan;
486 struct parkeduser *pu, *pl=NULL;
489 ast_log(LOG_WARNING, "Park requires an argument (extension number)\n");
493 park = atoi((char *)data);
494 pthread_mutex_lock(&parking_lock);
497 if (pu->parkingnum == park) {
501 parkinglot = pu->next;
506 pthread_mutex_unlock(&parking_lock);
512 /* Build a translator if necessary */
513 if (peer->format & chan->format)
516 nchan = ast_translator_create(chan, peer->format, AST_DIRECTION_BOTH);
517 /* This runs sorta backwards, since we give the incoming channel control, as if it
518 were the person called. */
519 if (option_verbose > 2)
520 ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
521 res = bridge_call(peer, nchan, 1);
523 ast_translator_destroy(nchan);
524 /* Simulate the PBX hanging up */
525 if (res != AST_PBX_KEEPALIVE)
529 /* XXX Play a message XXX */
530 if (option_verbose > 2)
531 ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to non-existant parked call %d\n", chan->name, park);
534 LOCAL_USER_REMOVE(u);
538 static int dial_exec(struct ast_channel *chan, void *data)
542 char *info, *peers, *timeout, *tech, *number, *rest, *cur;
543 struct localuser *outgoing=NULL, *tmp;
544 struct ast_channel *peer, *npeer;
547 char numsubst[AST_MAX_EXTENSION];
548 char restofit[AST_MAX_EXTENSION];
552 ast_log(LOG_WARNING, "Dial requires an argument (technology1/number1&technology2/number2...|optional timeout)\n");
558 /* Parse our arguments XXX Check for failure XXX */
559 info = malloc(strlen((char *)data) + AST_MAX_EXTENSION);
560 strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION);
561 peers = strtok(info, "|");
563 ast_log(LOG_WARNING, "Dial argument takes format (technology1/number1&technology2/number2...|optional timeout)\n");
566 timeout = strtok(NULL, "|");
569 cur = strtok(rest, "&");
570 /* Remember where to start next time */
571 rest = strtok(NULL, "\128");
572 /* Get a technology/[device:]number pair */
573 tech = strtok(cur, "/");
574 number = strtok(NULL, "&");
576 ast_log(LOG_WARNING, "Dial argument takes format (technology1/[device:]number1&technology2/[device:]number2...|optional timeout)\n");
579 tmp = malloc(sizeof(struct localuser));
581 ast_log(LOG_WARNING, "Out of memory\n");
584 tmp->allowredirect = 1;
585 strncpy(numsubst, number, sizeof(numsubst));
586 /* If we're dialing by extension, look at the extension to know what to dial */
587 if ((newnum = strstr(numsubst, "BYEXTENSION"))) {
588 strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit));
589 snprintf(newnum, sizeof(numsubst) - (newnum - numsubst), "%s%s", chan->exten,restofit);
590 /* By default, if we're dialing by extension, don't permit redirecting */
591 tmp->allowredirect = 0;
593 ast_log(LOG_DEBUG, "Dialing by extension %s\n", numsubst);
595 /* Request the peer */
596 tmp->chan = ast_request(tech, chan->format, numsubst);
598 /* If we can't, just go on to the next call */
599 ast_log(LOG_WARNING, "Unable to create channel of type '%s'\n", tech);
603 tmp->chan->appl = "AppDial";
604 tmp->chan->data = "(Outgoing Line)";
605 /* Place the call, but don't wait on the answer */
606 res = ast_call(tmp->chan, numsubst, 0);
608 /* Again, keep going even if there's an error */
610 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
611 else if (option_verbose > 2)
612 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", numsubst);
613 ast_hangup(tmp->chan);
617 if (option_verbose > 2)
618 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", numsubst);
619 /* Put them in the list of outgoing thingies... We're ready now.
620 XXX If we're forcibly removed, these outgoing calls won't get
622 tmp->stillgoing = -1;
623 tmp->next = outgoing;
627 to = atoi(timeout) * 1000;
630 peer = wait_for_answer(chan, outgoing, &to, &allowredir);
633 /* Musta gotten hung up */
636 /* Nobody answered, next please? */
642 /* Ah ha! Someone answered within the desired timeframe. Of course after this
643 we will always return with -1 so that it is hung up properly after the
645 hanguptree(outgoing, peer);
647 /* Build a translator if necessary */
648 if (peer->format & chan->format)
651 npeer = ast_translator_create(peer, chan->format, AST_DIRECTION_BOTH);
652 res = bridge_call(chan, npeer, allowredir);
654 ast_translator_destroy(npeer);
658 hanguptree(outgoing, NULL);
660 LOCAL_USER_REMOVE(u);
664 int unload_module(void)
666 STANDARD_HANGUP_LOCALUSERS;
667 return ast_unregister_application(app);
670 int load_module(void)
674 struct ast_context *con;
675 char exten[AST_MAX_EXTENSION];
676 con = ast_context_find(parking_con);
678 ast_log(LOG_ERROR, "Parking context '%s' does not exist\n", parking_con);
681 for(x=parking_start; x<=parking_stop;x++) {
682 snprintf(exten, sizeof(exten), "%d", x);
683 ast_add_extension2(con, 1, exten, 1, parkedcall, strdup(exten), free);
685 pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
686 res = ast_register_application(parkedcall, park_exec);
688 res = ast_register_application(app, dial_exec);
692 char *description(void)
700 STANDARD_USECOUNT(res);