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 QUEUE_STRATEGY_RINGALL 0
41 #define QUEUE_STRATEGY_ROUNDROBIN 1
42 #define QUEUE_STRATEGY_LEASTRECENT 2
43 #define QUEUE_STRATEGY_FEWESTCALLS 3
44 #define QUEUE_STRATEGY_RANDOM 4
46 static struct strategy {
50 { QUEUE_STRATEGY_RINGALL, "ringall" },
51 { QUEUE_STRATEGY_ROUNDROBIN, "roundrobin" },
52 { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
53 { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
54 { QUEUE_STRATEGY_RANDOM, "random" },
57 #define DEFAULT_RETRY 5
58 #define DEFAULT_TIMEOUT 15
59 #define RECHECK 1 /* Recheck every second to see we we're at the top yet */
61 static char *tdesc = "True Call Queueing";
63 static char *app = "Queue";
65 static char *synopsis = "Queue a call for a call queue";
67 static char *descrip =
68 " Queue(queuename[|options[|URL][|announceoverride]]):\n"
69 "Queues an incoming call in a particular call queue as defined in queues.conf.\n"
70 " This application returns -1 if the originating channel hangs up, or if the\n"
71 "call is bridged and either of the parties in the bridge terminate the call.\n"
72 "Returns 0 if the queue is full, nonexistant, or has no members.\n"
73 "The option string may contain zero or more of the following characters:\n"
74 " 't' -- allow the called user transfer the calling user\n"
75 " 'T' -- to allow the calling user to transfer the call.\n"
76 " 'd' -- data-quality (modem) call (minimum delay).\n"
77 " 'H' -- allow caller to hang up by hitting *.\n"
78 " In addition to transferring the call, a call may be parked and then picked\n"
79 "up by another user.\n"
80 " The optionnal URL will be sent to the called party if the channel supports\n"
84 static char *app_aqm = "AddQueueMember" ;
85 static char *app_aqm_synopsis = "Dynamically adds queue members" ;
86 static char *app_aqm_descrip =
87 " AddQueueMember(queuename[|interface]):\n"
88 "Dynamically adds interface to an existing queue\n"
89 "Returns -1 if there is an error.\n"
90 "Example: AddQueueMember(techsupport|SIP/3000)\n"
93 static char *app_rqm = "RemoveQueueMember" ;
94 static char *app_rqm_synopsis = "Dynamically removes queue members" ;
95 static char *app_rqm_descrip =
96 " RemoveQueueMember(queuename[|interface]):\n"
97 "Dynamically removes interface to an existing queue\n"
98 "Returns -1 if there is an error.\n"
99 "Example: RemoveQueueMember(techsupport|SIP/3000)\n"
105 /* We define a customer "local user" structure because we
106 use it not only for keeping track of what is in use but
107 also for keeping track of who we're dialing. */
110 struct ast_channel *chan;
115 int allowredirect_in;
116 int allowredirect_out;
121 struct member *member;
122 struct localuser *next;
128 struct ast_call_queue *parent; /* What queue is our parent */
129 char moh[80]; /* Name of musiconhold to be used */
130 char announce[80]; /* Announcement to play */
131 char context[80]; /* Context when user exits queue */
132 int pos; /* Where we are in the queue */
133 time_t start; /* When we started holding */
134 struct ast_channel *chan; /* Our channel */
135 struct queue_ent *next; /* The next queue entry */
139 char tech[80]; /* Technology */
140 char loc[256]; /* Location */
141 int penalty; /* Are we a last resort? */
143 int dynamic; /* Are we dynamically added? */
144 time_t lastcall; /* When last successful call was hungup */
145 struct member *next; /* Next member */
148 struct ast_call_queue {
150 char name[80]; /* Name of the queue */
151 char moh[80]; /* Name of musiconhold to be used */
152 char announce[80]; /* Announcement to play */
153 char context[80]; /* Announcement to play */
154 int strategy; /* Queueing strategy */
155 int announcetimeout; /* How often to announce their position */
156 int count; /* How many entries are in the queue */
157 int maxlen; /* Max number of entries in queue */
159 int dead; /* Whether this queue is dead or not */
160 int retry; /* Retry calling everyone after this amount of time */
161 int timeout; /* How long to wait for an answer */
163 /* Queue strategy things */
165 int rrpos; /* Round Robin - position */
166 int wrapped; /* Round Robin - wrapped around? */
168 struct member *members; /* Member channels to be tried */
169 struct queue_ent *head; /* Start of the actual queue */
170 struct ast_call_queue *next; /* Next call queue */
173 static struct ast_call_queue *queues = NULL;
174 static ast_mutex_t qlock = AST_MUTEX_INITIALIZER;
176 static char *int2strat(int strategy)
179 for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
180 if (strategy == strategies[x].strategy)
181 return strategies[x].name;
186 static int strat2int(char *strategy)
189 for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
190 if (!strcasecmp(strategy, strategies[x].name))
191 return strategies[x].strategy;
196 static int join_queue(char *queuename, struct queue_ent *qe)
198 struct ast_call_queue *q;
199 struct queue_ent *cur, *prev = NULL;
202 ast_mutex_lock(&qlock);
205 if (!strcasecmp(q->name, queuename)) {
206 /* This is our one */
207 ast_mutex_lock(&q->lock);
208 if (q->members && (!q->maxlen || (q->count < q->maxlen))) {
209 /* There's space for us, put us at the end */
221 /* Fix additional pointers and
226 strncpy(qe->moh, q->moh, sizeof(qe->moh));
227 strncpy(qe->announce, q->announce, sizeof(qe->announce));
228 strncpy(qe->context, q->context, sizeof(qe->context));
231 manager_event(EVENT_FLAG_CALL, "Join",
232 "Channel: %s\r\nCallerID: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\n",
233 qe->chan->name, (qe->chan->callerid ? qe->chan->callerid : "unknown"), q->name, qe->pos, q->count );
235 ast_log(LOG_NOTICE, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
238 ast_mutex_unlock(&q->lock);
243 ast_mutex_unlock(&qlock);
247 static void free_members(struct ast_call_queue *q, int all)
249 /* Free non-dynamic members */
250 struct member *curm, *next, *prev;
255 if (all || !curm->dynamic) {
267 static void destroy_queue(struct ast_call_queue *q)
269 struct ast_call_queue *cur, *prev = NULL;
270 ast_mutex_lock(&qlock);
275 prev->next = cur->next;
283 ast_mutex_unlock(&qlock);
288 static void leave_queue(struct queue_ent *qe)
290 struct ast_call_queue *q;
291 struct queue_ent *cur, *prev = NULL;
296 ast_mutex_lock(&q->lock);
304 /* Take us out of the queue */
305 manager_event(EVENT_FLAG_CALL, "Leave",
306 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\n",
307 qe->chan->name, q->name, q->count);
309 ast_log(LOG_NOTICE, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
311 /* Take us out of the queue */
313 prev->next = cur->next;
322 ast_mutex_unlock(&q->lock);
323 if (q->dead && !q->count) {
324 /* It's dead and nobody is in it, so kill it */
329 static void hanguptree(struct localuser *outgoing, struct ast_channel *exception)
331 /* Hang up a tree of stuff */
332 struct localuser *oo;
334 /* Hangup any existing lines we have open */
335 if (outgoing->chan && (outgoing->chan != exception))
336 ast_hangup(outgoing->chan);
338 outgoing=outgoing->next;
343 static int ring_entry(struct queue_ent *qe, struct localuser *tmp)
346 /* Request the peer */
347 tmp->chan = ast_request(tmp->tech, qe->chan->nativeformats, tmp->numsubst);
348 if (!tmp->chan) { /* If we can't, just go on to the next call */
350 ast_log(LOG_NOTICE, "Unable to create channel of type '%s'\n", cur->tech);
353 ast_cdr_busy(qe->chan->cdr);
357 tmp->chan->appl = "AppQueue";
358 tmp->chan->data = "(Outgoing Line)";
359 tmp->chan->whentohangup = 0;
360 if (tmp->chan->callerid)
361 free(tmp->chan->callerid);
363 free(tmp->chan->ani);
364 if (qe->chan->callerid)
365 tmp->chan->callerid = strdup(qe->chan->callerid);
367 tmp->chan->callerid = NULL;
369 tmp->chan->ani = strdup(qe->chan->ani);
371 tmp->chan->ani = NULL;
372 /* Presense of ADSI CPE on outgoing channel follows ours */
373 tmp->chan->adsicpe = qe->chan->adsicpe;
374 /* Place the call, but don't wait on the answer */
375 res = ast_call(tmp->chan, tmp->numsubst, 0);
377 /* Again, keep going even if there's an error */
379 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
380 else if (option_verbose > 2)
381 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->numsubst);
382 ast_hangup(tmp->chan);
387 if (option_verbose > 2)
388 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->numsubst);
392 static int ring_one(struct queue_ent *qe, struct localuser *outgoing)
394 struct localuser *cur;
395 struct localuser *best;
401 if (cur->stillgoing && /* Not already done */
402 !cur->chan && /* Isn't already going */
403 (!best || (cur->metric < bestmetric))) { /* We haven't found one yet, or it's better */
404 bestmetric = cur->metric;
410 if (!qe->parent->strategy) {
411 /* Ring everyone who shares this best metric (for ringall) */
414 if (cur->stillgoing && !cur->chan && (cur->metric == bestmetric)) {
415 ast_log(LOG_DEBUG, "(Parallel) Trying '%s/%s' with metric %d\n", cur->tech, cur->numsubst, cur->metric);
421 /* Ring just the best channel */
422 ast_log(LOG_DEBUG, "Trying '%s/%s' with metric %d\n", best->tech, best->numsubst, best->metric);
423 ring_entry(qe, best);
426 } while (best && !best->chan);
428 ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n");
434 static int valid_exit(struct queue_ent *qe, char digit)
437 if (!strlen(qe->context))
441 if (ast_exists_extension(qe->chan, qe->context, tmp, 1, qe->chan->callerid)) {
442 strncpy(qe->chan->context, qe->context, sizeof(qe->chan->context) - 1);
443 strncpy(qe->chan->exten, tmp, sizeof(qe->chan->exten) - 1);
444 qe->chan->priority = 0;
452 static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser *outgoing, int *to, int *allowredir_in, int *allowredir_out, int *allowdisconnect, char *digit)
454 char *queue = qe->parent->name;
462 struct localuser *peer = NULL;
463 struct ast_channel *watchers[MAX];
465 struct ast_channel *winner;
466 struct ast_channel *in = qe->chan;
468 while(*to && !peer) {
475 /* Keep track of important channels */
476 if (o->stillgoing && o->chan) {
477 watchers[pos++] = o->chan;
484 if (numlines == numbusies) {
485 ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
487 ast_log(LOG_NOTICE, "No one is answered queue %s\n", queue);
492 winner = ast_waitfor_n(watchers, pos, to);
495 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
497 if (option_verbose > 2)
498 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
500 *allowredir_in = o->allowredirect_in;
501 *allowredir_out = o->allowredirect_out;
502 *allowdisconnect = o->allowdisconnect;
504 } else if (o->chan && (o->chan == winner)) {
505 f = ast_read(winner);
507 if (f->frametype == AST_FRAME_CONTROL) {
508 switch(f->subclass) {
509 case AST_CONTROL_ANSWER:
510 /* This is our guy if someone answered. */
512 if (option_verbose > 2)
513 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
515 *allowredir_in = o->allowredirect_in;
516 *allowredir_out = o->allowredirect_out;
517 *allowdisconnect = o->allowdisconnect;
520 case AST_CONTROL_BUSY:
521 if (option_verbose > 2)
522 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
525 ast_cdr_busy(in->cdr);
528 if (qe->parent->strategy)
529 ring_one(qe, outgoing);
532 case AST_CONTROL_CONGESTION:
533 if (option_verbose > 2)
534 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
537 ast_cdr_busy(in->cdr);
540 if (qe->parent->strategy)
541 ring_one(qe, outgoing);
544 case AST_CONTROL_RINGING:
545 if (option_verbose > 2)
546 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
549 ast_indicate(in, AST_CONTROL_RINGING);
554 case AST_CONTROL_OFFHOOK:
555 /* Ignore going off hook */
558 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
566 if (qe->parent->strategy)
567 ring_one(qe, outgoing);
575 if (f && (f->frametype != AST_FRAME_VOICE))
576 printf("Frame type: %d, %d\n", f->frametype, f->subclass);
577 else if (!f || (f->frametype != AST_FRAME_VOICE))
578 printf("Hangup received on %s\n", in->name);
580 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
585 if (f && (f->frametype == AST_FRAME_DTMF) && allowdisconnect && (f->subclass == '*')) {
586 if (option_verbose > 3)
587 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
591 if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass != '*') && valid_exit(qe, f->subclass)) {
592 if (option_verbose > 3)
593 ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c", f->subclass);
599 if (!*to && (option_verbose > 2))
600 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
607 static int wait_our_turn(struct queue_ent *qe)
609 struct queue_ent *ch;
612 /* Atomically read the parent head -- does not need a lock */
613 ch = qe->parent->head;
614 /* If we are now at the top of the head, break out */
615 if (qe->parent->head == qe)
617 /* Wait a second before checking again */
618 res = ast_waitfordigit(qe->chan, RECHECK * 1000);
625 static int update_queue(struct ast_call_queue *q, struct localuser *user)
628 /* Since a reload could have taken place, we have to traverse the list to
629 be sure it's still valid */
630 ast_mutex_lock(&q->lock);
633 if (user->member == cur) {
634 time(&cur->lastcall);
640 ast_mutex_unlock(&q->lock);
644 static int calc_metric(struct ast_call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct localuser *tmp)
646 switch (q->strategy) {
647 case QUEUE_STRATEGY_RINGALL:
648 /* Everyone equal, except for penalty */
649 tmp->metric = mem->penalty * 1000000;
651 case QUEUE_STRATEGY_ROUNDROBIN:
654 /* No more channels, start over */
657 /* Prioritize next entry */
662 if (pos < q->rrpos) {
663 tmp->metric = 1000 + pos;
665 if (pos > q->rrpos) {
666 /* Indicate there is another priority */
671 tmp->metric += mem->penalty * 1000000;
673 case QUEUE_STRATEGY_RANDOM:
674 tmp->metric = rand() % 1000;
675 tmp->metric += mem->penalty * 1000000;
677 case QUEUE_STRATEGY_FEWESTCALLS:
678 tmp->metric = mem->calls;
679 tmp->metric += mem->penalty * 1000000;
681 case QUEUE_STRATEGY_LEASTRECENT:
685 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
686 tmp->metric += mem->penalty * 1000000;
689 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
695 static int try_calling(struct queue_ent *qe, char *options, char *announceoverride, char *url)
698 struct localuser *outgoing=NULL, *tmp = NULL;
701 int allowredir_out=0;
702 int allowdisconnect=0;
703 char restofit[AST_MAX_EXTENSION];
705 struct ast_channel *peer;
706 struct localuser *lpeer;
707 int res = 0, bridge = 0;
710 char *announce = NULL;
712 /* Hold the lock while we setup the outgoing calls */
713 ast_mutex_lock(&qe->parent->lock);
714 cur = qe->parent->members;
715 if (strlen(qe->announce))
716 announce = qe->announce;
717 if (announceoverride && strlen(announceoverride))
718 announce = announceoverride;
720 /* Get a technology/[device:]number pair */
721 tmp = malloc(sizeof(struct localuser));
723 ast_mutex_unlock(&qe->parent->lock);
724 ast_log(LOG_WARNING, "Out of memory\n");
727 memset(tmp, 0, sizeof(struct localuser));
728 tmp->stillgoing = -1;
730 if (strchr(options, 't'))
731 tmp->allowredirect_in = 1;
732 if (strchr(options, 'T'))
733 tmp->allowredirect_out = 1;
734 if (strchr(options, 'r'))
735 tmp->ringbackonly = 1;
736 if (strchr(options, 'm'))
737 tmp->musiconhold = 1;
738 if (strchr(options, 'd'))
739 tmp->dataquality = 1;
740 if (strchr(options, 'H'))
741 tmp->allowdisconnect = 1;
744 ast_log(LOG_DEBUG, "Queue with URL=%s_\n", url);
746 ast_log(LOG_DEBUG, "Simple queue (no URL)\n");
748 tmp->member = cur; /* Never directly dereference! Could change on reload */
749 strncpy(tmp->tech, cur->tech, sizeof(tmp->tech)-1);
750 strncpy(tmp->numsubst, cur->loc, sizeof(tmp->numsubst)-1);
751 /* If we're dialing by extension, look at the extension to know what to dial */
752 if ((newnum = strstr(tmp->numsubst, "BYEXTENSION"))) {
753 strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit)-1);
754 snprintf(newnum, sizeof(tmp->numsubst) - (newnum - tmp->numsubst), "%s%s", qe->chan->exten,restofit);
756 ast_log(LOG_DEBUG, "Dialing by extension %s\n", tmp->numsubst);
758 /* Special case: If we ring everyone, go ahead and ring them, otherwise
759 just calculate their metric for the appropriate strategy */
760 calc_metric(qe->parent, cur, x++, qe, tmp);
761 /* Put them in the list of outgoing thingies... We're ready now.
762 XXX If we're forcibly removed, these outgoing calls won't get
764 tmp->next = outgoing;
766 /* If this line is up, don't try anybody else */
767 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
772 if (qe->parent->timeout)
773 to = qe->parent->timeout * 1000;
776 ring_one(qe, outgoing);
777 ast_mutex_unlock(&qe->parent->lock);
778 lpeer = wait_for_answer(qe, outgoing, &to, &allowredir_in, &allowredir_out, &allowdisconnect, &digit);
785 /* Musta gotten hung up */
788 if (digit && valid_exit(qe, digit))
791 /* Nobody answered, next please? */
797 /* Ah ha! Someone answered within the desired timeframe. Of course after this
798 we will always return with -1 so that it is hung up properly after the
800 if (!strcmp(qe->chan->type,"Zap")) {
801 if (tmp->dataquality) zapx = 0;
802 ast_channel_setoption(qe->chan,AST_OPTION_TONE_VERIFY,&zapx,sizeof(char),0);
804 if (!strcmp(peer->type,"Zap")) {
805 if (tmp->dataquality) zapx = 0;
806 ast_channel_setoption(peer,AST_OPTION_TONE_VERIFY,&zapx,sizeof(char),0);
808 /* Update parameters for the queue */
809 update_queue(qe->parent, lpeer);
810 hanguptree(outgoing, peer);
811 /* Stop music on hold */
812 ast_moh_stop(qe->chan);
816 res2 = ast_autoservice_start(qe->chan);
818 res2 = ast_streamfile(peer, announce, peer->language);
820 res2 = ast_waitstream(peer, "");
821 res2 |= ast_autoservice_stop(qe->chan);
823 /* Agent must have hung up */
824 ast_log(LOG_WARNING, "Agent on %s hungup on the customer. They're going to be pissed.\n", peer->name);
829 /* If appropriate, log that we have a destination channel */
831 ast_cdr_setdestchan(qe->chan->cdr, peer->name);
832 /* Make sure channels are compatible */
833 res = ast_channel_make_compatible(qe->chan, peer);
835 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
839 /* Drop out of the queue at this point, to prepare for next caller */
842 if( url && strlen(url) && ast_channel_supports_html(peer) ) {
843 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
844 ast_channel_sendurl( peer, url );
846 bridge = ast_bridge_call(qe->chan, peer, allowredir_in, allowredir_out, allowdisconnect);
848 if(bridge != AST_PBX_NO_HANGUP_PEER)
851 if( bridge == 0 ) res=1; /* JDG: bridge successfull, leave app_queue */
852 else res = bridge; /* bridge error, stay in the queue */
855 hanguptree(outgoing, NULL);
859 static int wait_a_bit(struct queue_ent *qe)
861 /* Don't need to hold the lock while we setup the outgoing calls */
862 int retrywait = qe->parent->retry * 1000;
863 return ast_waitfordigit(qe->chan, retrywait);
868 static struct member * interface_exists( struct ast_call_queue * q, char * interface )
870 struct member * ret = NULL ;
878 while( mem != NULL ) {
879 sprintf( buf, "%s/%s", mem->tech, mem->loc);
881 if( strcmp( buf, interface ) == 0 ) {
894 static struct member * create_queue_node( char * interface )
896 struct member * cur ;
899 /* Add a new member */
901 cur = malloc(sizeof(struct member));
904 memset(cur, 0, sizeof(struct member));
905 strncpy(cur->tech, interface, sizeof(cur->tech) - 1);
906 if ((tmp = strchr(cur->tech, '/')))
908 if ((tmp = strchr(interface, '/'))) {
910 strncpy(cur->loc, tmp, sizeof(cur->loc) - 1);
912 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
919 static int rqm_exec(struct ast_channel *chan, void *data)
924 struct member * node ;
925 struct member * look ;
927 char tmpchan[256]="";
928 char *interface=NULL;
929 struct ast_call_queue *q;
933 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename|optional interface)\n");
937 LOCAL_USER_ADD(u); // not sure if we need this, but better be safe than sorry ;-)
939 /* Parse our arguments XXX Check for failure XXX */
940 strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
943 interface = strchr(queuename, '|');
949 strncpy(tmpchan, chan->name, sizeof(tmpchan) - 1);
950 interface = strrchr(tmpchan, '-');
957 if( ( q = queues) != NULL )
959 while( q && ( res != 0 ) && (!found) )
961 ast_mutex_lock(&q->lock);
962 if( strcmp( q->name, queuename) == 0 )
964 // found queue, try to remove interface
967 if( ( node = interface_exists( q, interface ) ) != NULL )
969 if( ( look = q->members ) == node )
972 q->members = node->next;
976 while( look != NULL )
977 if( look->next == node )
979 look->next = node->next ;
988 ast_log(LOG_NOTICE, "Removed interface '%s' to queue '%s'\n",
989 interface, queuename);
993 ast_log(LOG_WARNING, "Unable to remove interface '%s' from queue '%s': "
994 "Not there\n", interface, queuename);
997 ast_mutex_unlock(&q->lock);
1003 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", queuename);
1005 LOCAL_USER_REMOVE(u);
1011 static int aqm_exec(struct ast_channel *chan, void *data)
1014 struct localuser *u;
1017 char tmpchan[512]="";
1018 char *interface=NULL;
1019 struct ast_call_queue *q;
1020 struct member *save;
1024 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename|optional interface)\n");
1028 LOCAL_USER_ADD(u); // not sure if we need this, but better be safe than sorry ;-)
1030 /* Parse our arguments XXX Check for failure XXX */
1031 strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
1034 interface = strchr(queuename, '|');
1040 strncpy(tmpchan, chan->name, sizeof(tmpchan) - 1);
1041 interface = strrchr(tmpchan, '-');
1044 interface = tmpchan;
1048 if( ( q = queues) != NULL )
1050 while( q && ( res != 0 ) && (!found) )
1052 ast_mutex_lock(&q->lock);
1053 if( strcmp( q->name, queuename) == 0 )
1055 // found queue, try to enable interface
1058 if( interface_exists( q, interface ) == NULL )
1061 q->members = create_queue_node( interface ) ;
1063 if( q->members != NULL ) {
1064 q->members->dynamic = 1;
1065 q->members->next = save ;
1069 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", interface, queuename);
1073 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': "
1074 "Already there\n", interface, queuename);
1077 ast_mutex_unlock(&q->lock);
1083 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", queuename);
1085 LOCAL_USER_REMOVE(u);
1090 static int queue_exec(struct ast_channel *chan, void *data)
1093 struct localuser *u;
1096 char *options = NULL;
1098 char *announceoverride = NULL;
1100 /* Our queue entry */
1101 struct queue_ent qe;
1104 ast_log(LOG_WARNING, "Queue requires an argument (queuename|optional timeout|optional URL)\n");
1110 /* Parse our arguments XXX Check for failure XXX */
1111 strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
1114 options = strchr(queuename, '|');
1118 url = strchr(options, '|');
1122 announceoverride = strchr(url, '|');
1123 if (announceoverride) {
1124 *announceoverride = '\0';
1130 printf("queue: %s, options: %s, url: %s, announce: %s\n",
1131 queuename, options, url, announceoverride);
1132 /* Setup our queue entry */
1133 memset(&qe, 0, sizeof(qe));
1135 qe.start = time(NULL);
1136 if (!join_queue(queuename, &qe)) {
1137 /* Start music on hold */
1138 ast_moh_start(chan, qe.moh);
1140 res = wait_our_turn(&qe);
1141 /* If they hungup, return immediately */
1143 if (option_verbose > 2) {
1144 ast_verbose(VERBOSE_PREFIX_3 "User disconnected while waiting their turn\n");
1151 if (valid_exit(&qe, res))
1156 res = try_calling(&qe, options, announceoverride, url);
1159 res = wait_a_bit(&qe);
1161 if (option_verbose > 2) {
1162 ast_verbose(VERBOSE_PREFIX_3 "User disconnected when they almost made it\n");
1167 if (res && valid_exit(&qe, res))
1171 /* Don't allow return code > 0 */
1172 if (res > 0 && res != AST_PBX_KEEPALIVE) {
1178 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", queuename);
1181 LOCAL_USER_REMOVE(u);
1185 static void reload_queues(void)
1187 struct ast_call_queue *q, *ql, *qn;
1188 struct ast_config *cfg;
1190 struct ast_variable *var;
1191 struct member *prev, *cur;
1193 cfg = ast_load("queues.conf");
1195 ast_log(LOG_NOTICE, "No call queueing config file, so no call queues\n");
1198 ast_mutex_lock(&qlock);
1199 /* Mark all queues as dead for the moment */
1205 /* Chug through config file */
1206 cat = ast_category_browse(cfg, NULL);
1208 if (strcasecmp(cat, "general")) {
1209 /* Look for an existing one */
1212 if (!strcmp(q->name, cat))
1218 q = malloc(sizeof(struct ast_call_queue));
1221 memset(q, 0, sizeof(struct ast_call_queue));
1222 ast_mutex_init(&q->lock);
1223 strncpy(q->name, cat, sizeof(q->name));
1230 ast_mutex_lock(&q->lock);
1231 /* Re-initialize the queue */
1238 strcpy(q->announce, "");
1239 strcpy(q->context, "");
1242 /* find the end of any dynamic members */
1246 var = ast_variable_browse(cfg, cat);
1248 if (!strcasecmp(var->name, "member")) {
1249 /* Add a new member */
1250 cur = malloc(sizeof(struct member));
1252 memset(cur, 0, sizeof(struct member));
1253 strncpy(cur->tech, var->value, sizeof(cur->tech) - 1);
1254 if ((tmp = strchr(cur->tech, ','))) {
1257 cur->penalty = atoi(tmp);
1258 if (cur->penalty < 0)
1261 if ((tmp = strchr(cur->tech, '/')))
1263 if ((tmp = strchr(var->value, '/'))) {
1265 strncpy(cur->loc, tmp, sizeof(cur->loc) - 1);
1266 if ((tmp = strchr(cur->loc, ',')))
1269 ast_log(LOG_WARNING, "No location at line %d of queue.conf\n", var->lineno);
1276 } else if (!strcasecmp(var->name, "music")) {
1277 strncpy(q->moh, var->value, sizeof(q->moh) - 1);
1278 } else if (!strcasecmp(var->name, "announce")) {
1279 strncpy(q->announce, var->value, sizeof(q->announce) - 1);
1280 } else if (!strcasecmp(var->name, "context")) {
1281 strncpy(q->context, var->value, sizeof(q->context) - 1);
1282 } else if (!strcasecmp(var->name, "timeout")) {
1283 q->timeout = atoi(var->value);
1284 } else if (!strcasecmp(var->name, "retry")) {
1285 q->retry = atoi(var->value);
1286 } else if (!strcasecmp(var->name, "maxlen")) {
1287 q->maxlen = atoi(var->value);
1288 } else if (!strcasecmp(var->name, "strategy")) {
1289 q->strategy = strat2int(var->value);
1290 if (q->strategy < 0) {
1291 ast_log(LOG_WARNING, "'%s' isn't a valid strategy, using ringall instead\n", var->value);
1295 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queue.conf\n", cat, var->name, var->lineno);
1300 q->retry = DEFAULT_RETRY;
1302 q->timeout = DEFAULT_TIMEOUT;
1306 ast_mutex_unlock(&q->lock);
1313 cat = ast_category_browse(cfg, cat);
1328 ast_log(LOG_WARNING, "XXX Leaking a litttle memory :( XXX\n");
1333 ast_mutex_unlock(&qlock);
1336 static int queues_show(int fd, int argc, char **argv)
1338 struct ast_call_queue *q;
1339 struct queue_ent *qe;
1348 return RESULT_SHOWUSAGE;
1349 ast_mutex_lock(&qlock);
1352 ast_mutex_unlock(&qlock);
1353 ast_cli(fd, "No queues.\n");
1354 return RESULT_SUCCESS;
1357 ast_mutex_lock(&q->lock);
1359 snprintf(max, sizeof(max), "%d", q->maxlen);
1361 strcpy(max, "unlimited");
1362 ast_cli(fd, "%-12.12s has %d calls (max %s) in '%s' strategy\n", q->name, q->count, max, int2strat(q->strategy));
1364 ast_cli(fd, " Members: \n");
1365 for (mem = q->members; mem; mem = mem->next) {
1367 snprintf(max, sizeof(max) - 20, " with penalty %d", mem->penalty);
1371 strcat(max, " (dynamic)");
1373 snprintf(calls, sizeof(calls), " has taken %d calls (last was %ld secs ago)",
1374 mem->calls, (long)(time(NULL) - mem->lastcall));
1376 strcpy(calls, " has taken no calls yet");
1377 ast_cli(fd, " %s/%s%s%s\n", mem->tech, mem->loc, max, calls);
1380 ast_cli(fd, " No Members\n");
1383 ast_cli(fd, " Callers: \n");
1384 for (qe = q->head; qe; qe = qe->next)
1385 ast_cli(fd, " %d. %s (wait: %ld:%2.2ld)\n", pos++, qe->chan->name,
1386 (long)(now - qe->start) / 60, (long)(now - qe->start) % 60);
1388 ast_cli(fd, " No Callers\n");
1390 ast_mutex_unlock(&q->lock);
1393 ast_mutex_unlock(&qlock);
1394 return RESULT_SUCCESS;
1397 /* JDG: callback to display queues status in manager */
1398 static int manager_queues_show( struct mansession *s, struct message *m )
1400 char *a[] = { "show", "queues" };
1401 return queues_show( s->fd, 2, a );
1405 /* Dump queue status */
1406 static int manager_queues_status( struct mansession *s, struct message *m )
1410 char *id = astman_get_header(m,"ActionID");
1411 char idText[256] = "";
1412 struct ast_call_queue *q;
1413 struct queue_ent *qe;
1414 astman_send_ack(s, m, "Queue status will follow");
1416 ast_mutex_lock(&qlock);
1419 snprintf(idText,256,"ActionID: %s\r\n",id);
1422 ast_mutex_lock(&q->lock);
1423 ast_cli(s->fd, "Event: QueueParams\r\n"
1429 q->name, q->maxlen, q->count,idText);
1431 /* Do we care about queue members? */
1432 for (mem = q->members; mem; mem = mem->next)
1433 ast_cli(fd, " %s/%s\n", mem->tech, mem->loc);
1436 for (qe = q->head; qe; qe = qe->next)
1437 ast_cli(s->fd, "Event: QueueMember\r\n"
1445 q->name, pos++, qe->chan->name, (qe->chan->callerid ? qe->chan->callerid : ""), (long)(now - qe->start), idText);
1446 ast_mutex_unlock(&q->lock);
1449 ast_mutex_unlock(&qlock);
1450 return RESULT_SUCCESS;
1453 static char show_queues_usage[] =
1454 "Usage: show queues\n"
1455 " Provides summary information on call queues.\n";
1457 static struct ast_cli_entry cli_show_queues = {
1458 { "show", "queues", NULL }, queues_show,
1459 "Show status of queues", show_queues_usage, NULL };
1461 int unload_module(void)
1463 STANDARD_HANGUP_LOCALUSERS;
1464 ast_cli_unregister(&cli_show_queues);
1465 ast_manager_unregister( "Queues" );
1466 ast_manager_unregister( "QueueStatus" );
1467 return ast_unregister_application(app);
1470 int load_module(void)
1473 res = ast_register_application(app, queue_exec, synopsis, descrip);
1475 ast_cli_register(&cli_show_queues);
1476 ast_manager_register( "Queues", 0, manager_queues_show, "Queues" );
1477 ast_manager_register( "QueueStatus", 0, manager_queues_status, "Queue Status" );
1480 ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip) ;
1481 ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip) ;
1494 char *description(void)
1502 STANDARD_USECOUNT(res);
1508 return ASTERISK_GPL_KEY;