2 * Asterisk -- A telephony toolkit for Linux.
4 * True call queues with optional send URL on answer
6 * Copyright (C) 1999, Mark Spencer
8 * Mark Spencer <markster@linux-support.net>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
14 #include <asterisk/lock.h>
15 #include <asterisk/file.h>
16 #include <asterisk/logger.h>
17 #include <asterisk/channel.h>
18 #include <asterisk/pbx.h>
19 #include <asterisk/options.h>
20 #include <asterisk/module.h>
21 #include <asterisk/translate.h>
22 #include <asterisk/say.h>
23 #include <asterisk/parking.h>
24 #include <asterisk/musiconhold.h>
25 #include <asterisk/cli.h>
26 #include <asterisk/manager.h> /* JDG */
27 #include <asterisk/config.h>
35 #include <sys/signal.h>
36 #include <netinet/in.h>
40 #define DEFAULT_RETRY 5
41 #define DEFAULT_TIMEOUT 15
42 #define RECHECK 1 /* Recheck every second to see we we're at the top yet */
44 static char *tdesc = "True Call Queueing";
46 static char *app = "Queue";
48 static char *synopsis = "Queue a call for a call queue";
50 static char *descrip =
51 " Queue(queuename[|options[|URL][|announceoverride]]):\n"
52 "Queues an incoming call in a particular call queue as defined in queues.conf.\n"
53 " This application returns -1 if the originating channel hangs up, or if the\n"
54 "call is bridged and either of the parties in the bridge terminate the call.\n"
55 "Returns 0 if the queue is full, nonexistant, or has no members.\n"
56 "The option string may contain zero or more of the following characters:\n"
57 " 't' -- allow the called user transfer the calling user\n"
58 " 'T' -- to allow the calling user to transfer the call.\n"
59 " 'd' -- data-quality (modem) call (minimum delay).\n"
60 " 'H' -- allow caller to hang up by hitting *.\n"
61 " In addition to transferring the call, a call may be parked and then picked\n"
62 "up by another user.\n"
63 " The optionnal URL will be sent to the called party if the channel supports\n"
66 /* We define a customer "local user" structure because we
67 use it not only for keeping track of what is in use but
68 also for keeping track of who we're dialing. */
71 struct ast_channel *chan;
78 struct localuser *next;
84 struct ast_call_queue *parent; /* What queue is our parent */
85 char moh[80]; /* Name of musiconhold to be used */
86 char announce[80]; /* Announcement to play */
87 char context[80]; /* Context when user exits queue */
88 int pos; /* Where we are in the queue */
89 time_t start; /* When we started holding */
90 struct ast_channel *chan; /* Our channel */
91 struct queue_ent *next; /* The next queue entry */
95 char tech[80]; /* Technology */
96 char loc[256]; /* Location */
97 struct member *next; /* Next member */
100 struct ast_call_queue {
101 pthread_mutex_t lock;
102 char name[80]; /* Name of the queue */
103 char moh[80]; /* Name of musiconhold to be used */
104 char announce[80]; /* Announcement to play */
105 char context[80]; /* Announcement to play */
106 int announcetimeout; /* How often to announce their position */
107 int count; /* How many entries are in the queue */
108 int maxlen; /* Max number of entries in queue */
110 int dead; /* Whether this queue is dead or not */
111 int retry; /* Retry calling everyone after this amount of time */
112 int timeout; /* How long to wait for an answer */
114 struct member *members; /* Member channels to be tried */
115 struct queue_ent *head; /* Start of the actual queue */
116 struct ast_call_queue *next; /* Next call queue */
119 static struct ast_call_queue *queues = NULL;
120 static pthread_mutex_t qlock = AST_MUTEX_INITIALIZER;
123 static int join_queue(char *queuename, struct queue_ent *qe)
125 struct ast_call_queue *q;
126 struct queue_ent *cur, *prev = NULL;
129 ast_pthread_mutex_lock(&qlock);
132 if (!strcasecmp(q->name, queuename)) {
133 /* This is our one */
134 ast_pthread_mutex_lock(&q->lock);
135 if (q->members && (!q->maxlen || (q->count < q->maxlen))) {
136 /* There's space for us, put us at the end */
148 /* Fix additional pointers and
153 strncpy(qe->moh, q->moh, sizeof(qe->moh));
154 strncpy(qe->announce, q->announce, sizeof(qe->announce));
155 strncpy(qe->context, q->context, sizeof(qe->context));
158 manager_event(EVENT_FLAG_CALL, "Join",
159 "Channel: %s\r\nQueue: %s\r\nPosition: %d\r\n",
160 qe->chan->name, q->name, qe->pos );
163 ast_pthread_mutex_unlock(&q->lock);
168 ast_pthread_mutex_unlock(&qlock);
172 static void free_members(struct ast_call_queue *q)
174 struct member *curm, *next;
184 static void destroy_queue(struct ast_call_queue *q)
186 struct ast_call_queue *cur, *prev = NULL;
187 ast_pthread_mutex_lock(&qlock);
192 prev->next = cur->next;
200 ast_pthread_mutex_unlock(&qlock);
205 static void leave_queue(struct queue_ent *qe)
207 struct ast_call_queue *q;
208 struct queue_ent *cur, *prev = NULL;
213 ast_pthread_mutex_lock(&q->lock);
214 /* Take us out of the queue */
215 manager_event(EVENT_FLAG_CALL, "Leave",
216 "Channel: %s\r\nQueue: %s\r\n",
217 qe->chan->name, q->name );
223 /* Take us out of the queue */
225 prev->next = cur->next;
234 ast_pthread_mutex_unlock(&q->lock);
235 if (q->dead && !q->count) {
236 /* It's dead and nobody is in it, so kill it */
241 static void hanguptree(struct localuser *outgoing, struct ast_channel *exception)
243 /* Hang up a tree of stuff */
244 struct localuser *oo;
246 /* Hangup any existing lines we have open */
247 if (outgoing->chan != exception)
248 ast_hangup(outgoing->chan);
250 outgoing=outgoing->next;
257 static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localuser *outgoing, int *to, int *allowredir, int *allowdisconnect, char *queue)
266 struct ast_channel *peer = NULL;
267 struct ast_channel *watchers[MAX];
269 struct ast_channel *winner;
271 while(*to && !peer) {
278 /* Keep track of important channels */
280 watchers[pos++] = o->chan;
287 if (numlines == numbusies) {
288 ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
290 ast_log(LOG_NOTICE, "No one is answered queue %s\n", queue);
295 winner = ast_waitfor_n(watchers, pos, to);
298 if (o->stillgoing && (o->chan->_state == AST_STATE_UP)) {
300 if (option_verbose > 2)
301 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
303 *allowredir = o->allowredirect;
304 *allowdisconnect = o->allowdisconnect;
306 } else if (o->chan == winner) {
307 f = ast_read(winner);
309 if (f->frametype == AST_FRAME_CONTROL) {
310 switch(f->subclass) {
311 case AST_CONTROL_ANSWER:
312 /* This is our guy if someone answered. */
314 if (option_verbose > 2)
315 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
317 *allowredir = o->allowredirect;
318 *allowdisconnect = o->allowdisconnect;
321 case AST_CONTROL_BUSY:
322 if (option_verbose > 2)
323 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
326 ast_cdr_busy(in->cdr);
329 case AST_CONTROL_CONGESTION:
330 if (option_verbose > 2)
331 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
334 ast_cdr_busy(in->cdr);
337 case AST_CONTROL_RINGING:
338 if (option_verbose > 2)
339 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
342 ast_indicate(in, AST_CONTROL_RINGING);
347 case AST_CONTROL_OFFHOOK:
348 /* Ignore going off hook */
351 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
364 if (f && (f->frametype != AST_FRAME_VOICE))
365 printf("Frame type: %d, %d\n", f->frametype, f->subclass);
366 else if (!f || (f->frametype != AST_FRAME_VOICE))
367 printf("Hangup received on %s\n", in->name);
369 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
374 if (f && (f->frametype == AST_FRAME_DTMF) && allowdisconnect &&
375 (f->subclass == '*')) {
376 if (option_verbose > 3)
377 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
382 if (!*to && (option_verbose > 2))
383 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
390 static int wait_our_turn(struct queue_ent *qe)
392 struct queue_ent *ch;
395 /* Atomically read the parent head */
396 pthread_mutex_lock(&qe->parent->lock);
397 ch = qe->parent->head;
398 pthread_mutex_unlock(&qe->parent->lock);
399 /* If we are now at the top of the head, break out */
400 if (qe->parent->head == qe)
402 /* Wait a second before checking again */
403 res = ast_waitfordigit(qe->chan, RECHECK * 1000);
410 static int try_calling(struct queue_ent *qe, char *options, char *announceoverride, char *url)
413 struct localuser *outgoing=NULL, *tmp = NULL;
416 int allowdisconnect=0;
417 char numsubst[AST_MAX_EXTENSION];
418 char restofit[AST_MAX_EXTENSION];
420 struct ast_channel *peer;
421 int res = 0, bridge = 0;
422 char *announce = NULL;
423 /* Hold the lock while we setup the outgoing calls */
424 ast_pthread_mutex_lock(&qe->parent->lock);
425 cur = qe->parent->members;
426 if (strlen(qe->announce))
427 announce = qe->announce;
428 if (announceoverride && strlen(announceoverride))
429 announce = announceoverride;
431 /* Get a technology/[device:]number pair */
432 tmp = malloc(sizeof(struct localuser));
434 ast_log(LOG_WARNING, "Out of memory\n");
437 memset(tmp, 0, sizeof(struct localuser));
439 if (strchr(options, 't'))
440 tmp->allowredirect = 1;
441 if (strchr(options, 'r'))
442 tmp->ringbackonly = 1;
443 if (strchr(options, 'm'))
444 tmp->musiconhold = 1;
445 if (strchr(options, 'd'))
446 tmp->dataquality = 1;
447 if (strchr(options, 'H'))
448 tmp->allowdisconnect = 1;
451 ast_log(LOG_DEBUG, "Queue with URL=%s_\n", url);
453 ast_log(LOG_DEBUG, "Simple queue (no URL)\n");
455 strncpy(numsubst, cur->loc, sizeof(numsubst)-1);
456 /* If we're dialing by extension, look at the extension to know what to dial */
457 if ((newnum = strstr(numsubst, "BYEXTENSION"))) {
458 strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit)-1);
459 snprintf(newnum, sizeof(numsubst) - (newnum - numsubst), "%s%s", qe->chan->exten,restofit);
461 ast_log(LOG_DEBUG, "Dialing by extension %s\n", numsubst);
463 /* Request the peer */
464 tmp->chan = ast_request(cur->tech, qe->chan->nativeformats, numsubst);
466 /* If we can't, just go on to the next call */
468 ast_log(LOG_NOTICE, "Unable to create channel of type '%s'\n", cur->tech);
471 ast_cdr_busy(qe->chan->cdr);
477 /* Don't honor call forwarding on a queue! */
478 if (strlen(tmp->chan->call_forward)) {
479 if (option_verbose > 2)
480 ast_verbose(VERBOSE_PREFIX_3 "Forwarding call to '%s@%s'\n", tmp->chan->call_forward, tmp->chan->context);
481 /* Setup parameters */
482 strncpy(chan->exten, tmp->chan->call_forward, sizeof(chan->exten));
483 strncpy(chan->context, tmp->chan->context, sizeof(chan->context));
486 ast_hangup(tmp->chan);
492 tmp->chan->appl = "AppQueue";
493 tmp->chan->data = "(Outgoing Line)";
494 tmp->chan->whentohangup = 0;
495 if (tmp->chan->callerid)
496 free(tmp->chan->callerid);
498 free(tmp->chan->ani);
499 if (qe->chan->callerid)
500 tmp->chan->callerid = strdup(qe->chan->callerid);
502 tmp->chan->callerid = NULL;
504 tmp->chan->ani = strdup(qe->chan->ani);
506 tmp->chan->ani = NULL;
507 /* Presense of ADSI CPE on outgoing channel follows ours */
508 tmp->chan->adsicpe = qe->chan->adsicpe;
509 /* Place the call, but don't wait on the answer */
510 res = ast_call(tmp->chan, numsubst, 0);
512 /* Again, keep going even if there's an error */
514 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
515 else if (option_verbose > 2)
516 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", numsubst);
517 ast_hangup(tmp->chan);
522 if (option_verbose > 2)
523 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", numsubst);
524 /* Put them in the list of outgoing thingies... We're ready now.
525 XXX If we're forcibly removed, these outgoing calls won't get
527 tmp->stillgoing = -1;
528 tmp->next = outgoing;
530 /* If this line is up, don't try anybody else */
531 if (outgoing->chan->_state == AST_STATE_UP)
536 if (qe->parent->timeout)
537 to = qe->parent->timeout * 1000;
540 ast_pthread_mutex_unlock(&qe->parent->lock);
542 peer = wait_for_answer(qe->chan, outgoing, &to, &allowredir, &allowdisconnect, qe->parent->name);
545 /* Musta gotten hung up */
548 /* Nobody answered, next please? */
554 /* Ah ha! Someone answered within the desired timeframe. Of course after this
555 we will always return with -1 so that it is hung up properly after the
557 hanguptree(outgoing, peer);
558 /* Stop music on hold */
559 ast_moh_stop(qe->chan);
563 res2 = ast_streamfile(peer, announce, peer->language);
564 /* XXX Need a function to wait on *both* streams XXX */
566 res2 = ast_waitstream(peer, "");
570 /* Agent must have hung up */
571 ast_log(LOG_WARNING, "Agent on %s hungup on the customer. They're going to be pissed.\n", peer->name);
576 /* If appropriate, log that we have a destination channel */
578 ast_cdr_setdestchan(qe->chan->cdr, peer->name);
579 /* Make sure channels are compatible */
580 res = ast_channel_make_compatible(qe->chan, peer);
582 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
586 if (!strcmp(qe->chan->type,"Zap")) {
588 if (tmp->dataquality) x = 0;
589 ast_channel_setoption(qe->chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
591 if (!strcmp(peer->type,"Zap")) {
593 if (tmp->dataquality) x = 0;
594 ast_channel_setoption(peer,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
596 /* Drop out of the queue at this point, to prepare for next caller */
599 if( url && strlen(url) && ast_channel_supports_html(peer) ) {
600 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
601 ast_channel_sendurl( peer, url );
603 bridge = ast_bridge_call(qe->chan, peer, allowredir, allowdisconnect);
605 if( bridge == 0 ) res=1; /* JDG: bridge successfull, leave app_queue */
606 else res = bridge; /* bridge error, stay in the queue */
609 hanguptree(outgoing, NULL);
613 static int wait_a_bit(struct queue_ent *qe)
616 /* Hold the lock while we setup the outgoing calls */
617 ast_pthread_mutex_lock(&qe->parent->lock);
618 retrywait = qe->parent->retry * 1000;
619 ast_pthread_mutex_unlock(&qe->parent->lock);
620 return ast_waitfordigit(qe->chan, retrywait);
623 static int valid_exit(struct queue_ent *qe, char digit)
626 if (!strlen(qe->context))
630 if (ast_exists_extension(qe->chan, qe->context, tmp, 1, qe->chan->callerid)) {
631 strncpy(qe->chan->context, qe->context, sizeof(qe->chan->context) - 1);
632 strncpy(qe->chan->exten, tmp, sizeof(qe->chan->exten) - 1);
633 qe->chan->priority = 0;
639 static int queue_exec(struct ast_channel *chan, void *data)
645 char *options = NULL;
647 char *announceoverride = NULL;
649 /* Our queue entry */
653 ast_log(LOG_WARNING, "Queue requires an argument (queuename|optional timeout|optional URL)\n");
659 /* Parse our arguments XXX Check for failure XXX */
660 strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
663 options = strchr(queuename, '|');
667 url = strchr(options, '|');
671 announceoverride = strchr(url, '|');
672 if (announceoverride) {
673 *announceoverride = '\0';
679 printf("queue: %s, options: %s, url: %s, announce: %s\n",
680 queuename, options, url, announceoverride);
681 /* Setup our queue entry */
682 memset(&qe, 0, sizeof(qe));
684 qe.start = time(NULL);
685 if (!join_queue(queuename, &qe)) {
686 /* Start music on hold */
687 ast_moh_start(chan, qe.moh);
689 res = wait_our_turn(&qe);
690 /* If they hungup, return immediately */
692 if (option_verbose > 2) {
693 ast_verbose(VERBOSE_PREFIX_3 "User disconnected while waiting their turn\n");
700 if (valid_exit(&qe, res))
705 res = try_calling(&qe, options, announceoverride, url);
708 res = wait_a_bit(&qe);
710 if (option_verbose > 2) {
711 ast_verbose(VERBOSE_PREFIX_3 "User disconnected when they almost made it\n");
716 if (res && valid_exit(&qe, res))
720 /* Don't allow return code > 0 */
721 if (res > 0 && res != AST_PBX_KEEPALIVE)
726 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", queuename);
729 LOCAL_USER_REMOVE(u);
733 static void reload_queues(void)
735 struct ast_call_queue *q, *ql, *qn;
736 struct ast_config *cfg;
738 struct ast_variable *var;
739 struct member *prev, *cur;
741 cfg = ast_load("queues.conf");
743 ast_log(LOG_NOTICE, "No call queueing config file, so no call queues\n");
746 ast_pthread_mutex_lock(&qlock);
747 /* Mark all queues as dead for the moment */
753 /* Chug through config file */
754 cat = ast_category_browse(cfg, NULL);
756 if (strcasecmp(cat, "general")) {
757 /* Look for an existing one */
760 if (!strcmp(q->name, cat))
766 q = malloc(sizeof(struct ast_call_queue));
769 memset(q, 0, sizeof(struct ast_call_queue));
770 ast_pthread_mutex_init(&q->lock);
771 strncpy(q->name, cat, sizeof(q->name));
778 ast_pthread_mutex_lock(&q->lock);
779 /* Re-initialize the queue */
786 strcpy(q->announce, "");
787 strcpy(q->context, "");
789 var = ast_variable_browse(cfg, cat);
791 if (!strcasecmp(var->name, "member")) {
792 /* Add a new member */
793 cur = malloc(sizeof(struct member));
795 memset(cur, 0, sizeof(struct member));
796 strncpy(cur->tech, var->value, sizeof(cur->tech) - 1);
797 if ((tmp = strchr(cur->tech, '/')))
799 if ((tmp = strchr(var->value, '/'))) {
801 strncpy(cur->loc, tmp, sizeof(cur->loc) - 1);
803 ast_log(LOG_WARNING, "No location at line %d of queue.conf\n", var->lineno);
810 } else if (!strcasecmp(var->name, "music")) {
811 strncpy(q->moh, var->value, sizeof(q->moh) - 1);
812 } else if (!strcasecmp(var->name, "announce")) {
813 strncpy(q->announce, var->value, sizeof(q->announce) - 1);
814 } else if (!strcasecmp(var->name, "context")) {
815 strncpy(q->context, var->value, sizeof(q->context) - 1);
816 } else if (!strcasecmp(var->name, "timeout")) {
817 q->timeout = atoi(var->value);
818 } else if (!strcasecmp(var->name, "retry")) {
819 q->retry = atoi(var->value);
820 } else if (!strcasecmp(var->name, "maxlen")) {
821 q->maxlen = atoi(var->value);
823 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queue.conf\n", cat, var->name, var->lineno);
828 q->retry = DEFAULT_RETRY;
830 q->timeout = DEFAULT_TIMEOUT;
834 ast_pthread_mutex_unlock(&q->lock);
841 cat = ast_category_browse(cfg, cat);
856 ast_log(LOG_WARNING, "XXX Leaking a litttle memory :( XXX\n");
861 ast_pthread_mutex_unlock(&qlock);
864 static int queues_show(int fd, int argc, char **argv)
866 struct ast_call_queue *q;
867 struct queue_ent *qe;
875 return RESULT_SHOWUSAGE;
878 ast_cli(fd, "No queues.\n");
879 return RESULT_SUCCESS;
882 ast_pthread_mutex_lock(&q->lock);
884 snprintf(max, sizeof(max), "%d", q->maxlen);
886 strcpy(max, "unlimited");
887 ast_cli(fd, "%-12.12s has %d calls (max %s)\n", q->name, q->count, max);
889 ast_cli(fd, " Members: \n");
890 for (mem = q->members; mem; mem = mem->next)
891 ast_cli(fd, " %s/%s\n", mem->tech, mem->loc);
893 ast_cli(fd, " No Members\n");
896 ast_cli(fd, " Callers: \n");
897 for (qe = q->head; qe; qe = qe->next)
898 ast_cli(fd, " %d. %s (wait: %d:%02.2d)\n", pos++, qe->chan->name,
899 (now - qe->start) / 60, (now - qe->start) % 60);
901 ast_cli(fd, " No Callers\n");
903 ast_pthread_mutex_unlock(&q->lock);
906 return RESULT_SUCCESS;
909 /* JDG: callback to display queues status in manager */
910 static int manager_queues_show( struct mansession *s, struct message *m )
912 char *a[] = { "show", "queues" };
913 return queues_show( s->fd, 2, a );
916 static char show_queues_usage[] =
917 "Usage: show queues\n"
918 " Provides summary information on call queues.\n";
920 static struct ast_cli_entry cli_show_queues = {
921 { "show", "queues", NULL }, queues_show,
922 "Show status of queues", show_queues_usage, NULL };
924 int unload_module(void)
926 STANDARD_HANGUP_LOCALUSERS;
927 ast_cli_unregister(&cli_show_queues);
928 ast_manager_unregister( "Queues" );
929 return ast_unregister_application(app);
932 int load_module(void)
935 res = ast_register_application(app, queue_exec, synopsis, descrip);
937 ast_cli_register(&cli_show_queues);
938 ast_manager_register( "Queues", 0, manager_queues_show, "Queues" );
950 char *description(void)
958 STANDARD_USECOUNT(res);
964 return ASTERISK_GPL_KEY;