2 * Asterisk -- A telephony toolkit for Linux.
4 * True call queues with optional send URL on answer
6 * Copyright (C) 1999-2004, Digium, Inc.
8 * Mark Spencer <markster@digium.com>
10 * 2004-11-25: Persistent Dynamic Members added by:
11 * NetNation Communications (www.netnation.com)
12 * Kevin Lindsay <kevinl@netnation.com>
14 * Each dynamic agent in each queue is now stored in the astdb.
15 * When asterisk is restarted, each agent will be automatically
16 * readded into their recorded queues. This feature can be
17 * configured with the 'peristent_members=<1|0>' KVP under the
18 * '[general]' group in queues.conf. The default is on.
20 * 2004-06-04: Priorities in queues added by inAccess Networks (work funded by Hellas On Line (HOL) www.hol.gr).
22 * These features added by David C. Troy <dave@toad.net>:
23 * - Per-queue holdtime calculation
24 * - Estimated holdtime announcement
25 * - Position announcement
26 * - Abandoned/completed call counters
27 * - Failout timer passed as optional app parameter
28 * - Optional monitoring of calls, started when call is answered
30 * Patch Version 1.07 2003-12-24 01
32 * Added servicelevel statistic by Michiel Betel <michiel@betel.nl>
33 * Added Priority jumping code for adding and removing queue members by Jonathan Stanton <asterisk@doilooklikeicare.com>
35 * Fixed to work with CVS as of 2004-02-25 and released as 1.07a
36 * by Matthew Enger <m.enger@xi.com.au>
38 * This program is free software, distributed under the terms of
39 * the GNU General Public License
42 #include <asterisk/lock.h>
43 #include <asterisk/file.h>
44 #include <asterisk/logger.h>
45 #include <asterisk/channel.h>
46 #include <asterisk/pbx.h>
47 #include <asterisk/options.h>
48 #include <asterisk/module.h>
49 #include <asterisk/translate.h>
50 #include <asterisk/say.h>
51 #include <asterisk/features.h>
52 #include <asterisk/musiconhold.h>
53 #include <asterisk/cli.h>
54 #include <asterisk/manager.h>
55 #include <asterisk/config.h>
56 #include <asterisk/monitor.h>
57 #include <asterisk/utils.h>
58 #include <asterisk/causes.h>
59 #include <asterisk/astdb.h>
67 #include <sys/signal.h>
68 #include <netinet/in.h>
70 #include "../astconf.h"
72 #define QUEUE_STRATEGY_RINGALL 0
73 #define QUEUE_STRATEGY_ROUNDROBIN 1
74 #define QUEUE_STRATEGY_LEASTRECENT 2
75 #define QUEUE_STRATEGY_FEWESTCALLS 3
76 #define QUEUE_STRATEGY_RANDOM 4
77 #define QUEUE_STRATEGY_RRMEMORY 5
79 static struct strategy {
83 { QUEUE_STRATEGY_RINGALL, "ringall" },
84 { QUEUE_STRATEGY_ROUNDROBIN, "roundrobin" },
85 { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
86 { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
87 { QUEUE_STRATEGY_RANDOM, "random" },
88 { QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
91 #define DEFAULT_RETRY 5
92 #define DEFAULT_TIMEOUT 15
93 #define RECHECK 1 /* Recheck every second to see we we're at the top yet */
95 #define RES_OKAY 0 /* Action completed */
96 #define RES_EXISTS (-1) /* Entry already exists */
97 #define RES_OUTOFMEMORY (-2) /* Out of memory */
98 #define RES_NOSUCHQUEUE (-3) /* No such queue */
100 static char *tdesc = "True Call Queueing";
102 static char *app = "Queue";
104 static char *synopsis = "Queue a call for a call queue";
106 static char *descrip =
107 " Queue(queuename[|options[|URL][|announceoverride][|timeout]]):\n"
108 "Queues an incoming call in a particular call queue as defined in queues.conf.\n"
109 " This application returns -1 if the originating channel hangs up, or if the\n"
110 "call is bridged and either of the parties in the bridge terminate the call.\n"
111 "Returns 0 if the queue is full, nonexistant, or has no members.\n"
112 "The option string may contain zero or more of the following characters:\n"
113 " 't' -- allow the called user transfer the calling user\n"
114 " 'T' -- to allow the calling user to transfer the call.\n"
115 " 'd' -- data-quality (modem) call (minimum delay).\n"
116 " 'h' -- allow callee to hang up by hitting *.\n"
117 " 'H' -- allow caller to hang up by hitting *.\n"
118 " 'n' -- no retries on the timeout; will exit this application and \n"
119 " go to the next step.\n"
120 " 'r' -- ring instead of playing MOH\n"
121 " In addition to transferring the call, a call may be parked and then picked\n"
122 "up by another user.\n"
123 " The optional URL will be sent to the called party if the channel supports\n"
125 " The timeout will cause the queue to fail out after a specified number of\n"
126 "seconds, checked between each queues.conf 'timeout' and 'retry' cycle.\n";
129 static char *app_aqm = "AddQueueMember" ;
130 static char *app_aqm_synopsis = "Dynamically adds queue members" ;
131 static char *app_aqm_descrip =
132 " AddQueueMember(queuename[|interface[|penalty]]):\n"
133 "Dynamically adds interface to an existing queue.\n"
134 "If the interface is already in the queue and there exists an n+101 priority\n"
135 "then it will then jump to this priority. Otherwise it will return an error\n"
136 "Returns -1 if there is an error.\n"
137 "Example: AddQueueMember(techsupport|SIP/3000)\n"
140 static char *app_rqm = "RemoveQueueMember" ;
141 static char *app_rqm_synopsis = "Dynamically removes queue members" ;
142 static char *app_rqm_descrip =
143 " RemoveQueueMember(queuename[|interface]):\n"
144 "Dynamically removes interface to an existing queue\n"
145 "If the interface is NOT in the queue and there exists an n+101 priority\n"
146 "then it will then jump to this priority. Otherwise it will return an error\n"
147 "Returns -1 if there is an error.\n"
148 "Example: RemoveQueueMember(techsupport|SIP/3000)\n"
151 static char *app_pqm = "PauseQueueMember" ;
152 static char *app_pqm_synopsis = "Pauses a queue member" ;
153 static char *app_pqm_descrip =
154 " PauseQueueMember([queuename]|interface):\n"
155 "Pauses (blocks calls for) a queue member.\n"
156 "The given interface will be paused in the given queue. This prevents\n"
157 "any calls from being sent from the queue to the interface until it is\n"
158 "unpaused with UnpauseQueueMember or the manager interface. If no\n"
159 "queuename is given, the interface is paused in every queue it is a\n"
160 "member of. If the interface is not in the named queue, or if no queue\n"
161 "is given and the interface is not in any queue, it will jump to\n"
162 " priority n+101, if it exists. Returns -1 if the interface is not\n"
163 "found and no extension to jump to exists, 0 otherwise.\n"
164 "Example: PauseQueueMember(|SIP/3000)\n";
166 static char *app_upqm = "UnpauseQueueMember" ;
167 static char *app_upqm_synopsis = "Unpauses a queue member" ;
168 static char *app_upqm_descrip =
169 " UnpauseQueueMember([queuename]|interface):\n"
170 "Unpauses (resumes calls to) a queue member.\n"
171 "This is the counterpart to PauseQueueMember and operates exactly the\n"
172 "same way, except it unpauses instead of pausing the given interface.\n"
173 "Example: UnpauseQueueMember(|SIP/3000)\n";
175 /* Persistent Members astdb family */
176 static const char *pm_family = "/Queue/PersistentMembers";
177 /* The maximum lengh of each persistent member queue database entry */
178 #define PM_MAX_LEN 2048
179 /* queues.conf [general] option */
180 static int queue_persistent_members = 0;
181 /* queues.conf per-queue weight option */
182 static int use_weight = 0;
185 #define QUEUE_FLAG_RINGBACKONLY (1 << 0)
186 #define QUEUE_FLAG_MUSICONHOLD (1 << 1)
187 #define QUEUE_FLAG_DATAQUALITY (1 << 2)
188 #define QUEUE_FLAG_REDIR_IN (1 << 3)
189 #define QUEUE_FLAG_REDIR_OUT (1 << 4)
190 #define QUEUE_FLAG_DISCON_IN (1 << 5)
191 #define QUEUE_FLAG_DISCON_OUT (1 << 6)
192 #define QUEUE_FLAG_MONJOIN (1 << 7) /* Should we join the two files when we are done with the call */
193 #define QUEUE_FLAG_DEAD (1 << 8) /* Whether the queue is dead or not */
194 #define QUEUE_FLAG_JOINEMPTY (1 << 9) /* Do we care if the queue has no members? */
195 #define QUEUE_FLAG_EVENTWHENCALLED (1 << 10) /* Generate an event when the agent is called (before pickup) */
196 #define QUEUE_FLAG_LEAVEWHENEMPTY (1 << 11) /* If all agents leave the queue, remove callers from the queue */
197 #define QUEUE_FLAG_REPORTHOLDTIME (1 << 12) /* Should we report caller hold time to answering member? */
198 #define QUEUE_FLAG_WRAPPED (1 << 13) /* Round Robin - wrapped around? */
199 #define QUEUE_FLAG_TIMEOUTRESTART (1 << 14) /* Restart timer when member call */
201 /* We define a custom "local user" structure because we
202 use it not only for keeping track of what is in use but
203 also for keeping track of who we're dialing. */
206 struct ast_channel *chan;
211 unsigned int flags; /* flag bits */
213 struct member *member;
214 struct localuser *next;
220 struct ast_call_queue *parent; /* What queue is our parent */
221 char moh[80]; /* Name of musiconhold to be used */
222 char announce[80]; /* Announcement to play for member when call is answered */
223 char context[80]; /* Context when user exits queue */
224 int pos; /* Where we are in the queue */
225 int prio; /* Our priority */
226 int last_pos_said; /* Last position we told the user */
227 time_t last_pos; /* Last time we told the user their position */
228 int opos; /* Where we started in the queue */
229 int handled; /* Whether our call was handled */
230 time_t start; /* When we started holding */
231 time_t expire; /* When this entry should expire (time out of queue) */
232 struct ast_channel *chan; /* Our channel */
233 struct queue_ent *next; /* The next queue entry */
237 char interface[80]; /* Technology/Location */
238 int penalty; /* Are we a last resort? */
239 int calls; /* Number of calls serviced by this member */
240 int dynamic; /* Are we dynamically added? */
241 int status; /* Status of queue member */
242 int paused; /* Are we paused (not accepting calls)? */
243 time_t lastcall; /* When last successful call was hungup */
244 struct member *next; /* Next member */
247 struct ast_call_queue {
249 char name[80]; /* Name of the queue */
250 char moh[80]; /* Name of musiconhold to be used */
251 char announce[80]; /* Announcement to play when call is answered */
252 char context[80]; /* Context for this queue */
253 unsigned int flags; /* flag bits */
254 int strategy; /* Queueing strategy */
255 int announcefrequency; /* How often to announce their position */
256 int roundingseconds; /* How many seconds do we round to? */
257 int announceholdtime; /* When to announce holdtime: 0 = never, -1 = every announcement, 1 = only once */
258 int holdtime; /* Current avg holdtime for this queue, based on recursive boxcar filter */
259 int callscompleted; /* Number of queue calls completed */
260 int callsabandoned; /* Number of queue calls abandoned */
261 int servicelevel; /* seconds setting for servicelevel*/
262 int callscompletedinsl; /* Number of queue calls answered with servicelevel*/
263 char monfmt[8]; /* Format to use when recording calls */
264 char sound_next[80]; /* Sound file: "Your call is now first in line" (def. queue-youarenext) */
265 char sound_thereare[80]; /* Sound file: "There are currently" (def. queue-thereare) */
266 char sound_calls[80]; /* Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting)*/
267 char sound_holdtime[80]; /* Sound file: "The current estimated total holdtime is" (def. queue-holdtime) */
268 char sound_minutes[80]; /* Sound file: "minutes." (def. queue-minutes) */
269 char sound_lessthan[80]; /* Sound file: "less-than" (def. queue-lessthan) */
270 char sound_seconds[80]; /* Sound file: "seconds." (def. queue-seconds) */
271 char sound_thanks[80]; /* Sound file: "Thank you for your patience." (def. queue-thankyou) */
272 char sound_reporthold[80]; /* Sound file: "Hold time" (def. queue-reporthold) */
274 int count; /* How many entries are in the queue */
275 int maxlen; /* Max number of entries in queue */
276 int wrapuptime; /* Wrapup Time */
278 int retry; /* Retry calling everyone after this amount of time */
279 int timeout; /* How long to wait for an answer */
280 int weight; /* This queue's respective weight */
282 /* Queue strategy things */
283 int rrpos; /* Round Robin - position */
284 int memberdelay; /* Seconds to delay connecting member to caller */
286 struct member *members; /* Member channels to be tried */
287 struct queue_ent *head; /* Start of the actual queue */
288 struct ast_call_queue *next; /* Next call queue */
291 static struct ast_call_queue *queues = NULL;
292 AST_MUTEX_DEFINE_STATIC(qlock);
295 static char *int2strat(int strategy)
298 for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
299 if (strategy == strategies[x].strategy)
300 return strategies[x].name;
305 static int strat2int(char *strategy)
308 for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
309 if (!strcasecmp(strategy, strategies[x].name))
310 return strategies[x].strategy;
315 /* Insert the 'new' entry after the 'prev' entry of queue 'q' */
316 static inline void insert_entry(struct ast_call_queue *q,
317 struct queue_ent *prev, struct queue_ent *new, int *pos)
319 struct queue_ent *cur;
336 static int has_no_members(struct ast_call_queue *q)
338 struct member *member;
341 while(empty && member) {
342 switch(member->status) {
343 case AST_DEVICE_UNAVAILABLE:
344 case AST_DEVICE_INVALID:
345 /* Not logged on, etc */
351 member = member->next;
361 static void *changethread(void *data)
363 struct ast_call_queue *q;
364 struct statechange *sc = data;
369 technology = ast_strdupa(sc->dev);
370 loc = strchr(technology, '/');
375 ast_log(LOG_WARNING, "Can't change device '%s' with no technology!\n", sc->dev);
380 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d'\n", technology, loc, sc->state);
381 ast_mutex_lock(&qlock);
382 for (q = queues; q; q = q->next) {
383 ast_mutex_lock(&q->lock);
386 if (!strcasecmp(sc->dev, cur->interface)) {
387 if (cur->status != sc->state) {
388 cur->status = sc->state;
389 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
398 q->name, cur->interface, cur->dynamic ? "dynamic" : "static",
399 cur->penalty, cur->calls, cur->lastcall, cur->status, cur->paused);
404 ast_mutex_unlock(&q->lock);
406 ast_mutex_unlock(&qlock);
408 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d'\n", technology, loc, sc->state);
413 static int statechange_queue(const char *dev, int state, void *ign)
415 /* Avoid potential for deadlocks by spawning a new thread to handle
417 struct statechange *sc;
421 sc = malloc(sizeof(struct statechange) + strlen(dev) + 1);
424 strcpy(sc->dev, dev);
425 pthread_attr_init(&attr);
426 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
427 if (ast_pthread_create(&t, &attr, changethread, sc)) {
428 ast_log(LOG_WARNING, "Failed to create update thread!\n");
435 static int join_queue(char *queuename, struct queue_ent *qe)
437 struct ast_call_queue *q;
438 struct queue_ent *cur, *prev = NULL;
443 ast_mutex_lock(&qlock);
444 for (q = queues; q; q = q->next) {
445 if (!strcasecmp(q->name, queuename)) {
446 /* This is our one */
447 ast_mutex_lock(&q->lock);
448 if ((!has_no_members(q) || ast_test_flag(q, QUEUE_FLAG_JOINEMPTY)) && (!q->maxlen || (q->count < q->maxlen))) {
449 /* There's space for us, put us at the right position inside
451 * Take into account the priority of the calling user */
456 /* We have higher priority than the current user, enter
457 * before him, after all the other users with priority
458 * higher or equal to our priority. */
459 if ((!inserted) && (qe->prio > cur->prio)) {
460 insert_entry(q, prev, qe, &pos);
467 /* No luck, join at the end of the queue */
469 insert_entry(q, prev, qe, &pos);
470 strncpy(qe->moh, q->moh, sizeof(qe->moh) - 1);
471 strncpy(qe->announce, q->announce, sizeof(qe->announce) - 1);
472 strncpy(qe->context, q->context, sizeof(qe->context) - 1);
475 manager_event(EVENT_FLAG_CALL, "Join",
476 "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\n",
478 qe->chan->cid.cid_num ? qe->chan->cid.cid_num : "unknown",
479 qe->chan->cid.cid_name ? qe->chan->cid.cid_name : "unknown",
480 q->name, qe->pos, q->count );
482 ast_log(LOG_NOTICE, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
485 ast_mutex_unlock(&q->lock);
489 ast_mutex_unlock(&qlock);
493 static void free_members(struct ast_call_queue *q, int all)
495 /* Free non-dynamic members */
496 struct member *curm, *next, *prev;
501 if (all || !curm->dynamic) {
513 static void destroy_queue(struct ast_call_queue *q)
515 struct ast_call_queue *cur, *prev = NULL;
516 ast_mutex_lock(&qlock);
517 for (cur = queues; cur; cur = cur->next) {
520 prev->next = cur->next;
527 ast_mutex_unlock(&qlock);
529 ast_mutex_destroy(&q->lock);
533 static int play_file(struct ast_channel *chan, char *filename)
537 ast_stopstream(chan);
538 res = ast_streamfile(chan, filename, chan->language);
541 res = ast_waitstream(chan, "");
546 ast_log(LOG_WARNING, "ast_streamfile failed on %s \n", chan->name);
549 ast_stopstream(chan);
554 static int say_position(struct queue_ent *qe)
556 int res = 0, avgholdmins, avgholdsecs;
559 /* Check to see if this is ludicrous -- if we just announced position, don't do it again*/
561 if ( (now - qe->last_pos) < 15 )
564 /* If either our position has changed, or we are over the freq timer, say position */
565 if ( (qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency) )
568 ast_moh_stop(qe->chan);
569 /* Say we're next, if we are */
571 res += play_file(qe->chan, qe->parent->sound_next);
574 res += play_file(qe->chan, qe->parent->sound_thereare);
575 res += ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */
576 res += play_file(qe->chan, qe->parent->sound_calls);
578 /* Round hold time to nearest minute */
579 avgholdmins = abs(( (qe->parent->holdtime + 30) - (now - qe->start) ) / 60);
581 /* If they have specified a rounding then round the seconds as well */
582 if(qe->parent->roundingseconds) {
583 avgholdsecs = (abs(( (qe->parent->holdtime + 30) - (now - qe->start) )) - 60 * avgholdmins) / qe->parent->roundingseconds;
584 avgholdsecs*= qe->parent->roundingseconds;
589 if (option_verbose > 2)
590 ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
592 /* If the hold time is >1 min, if it's enabled, and if it's not
593 supposed to be only once and we have already said it, say it */
594 if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) && (!(qe->parent->announceholdtime==1 && qe->last_pos)) ) {
595 res += play_file(qe->chan, qe->parent->sound_holdtime);
597 if (avgholdmins < 2) {
598 res += play_file(qe->chan, qe->parent->sound_lessthan);
599 res += ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, (char *)NULL);
601 res += ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, (char*) NULL);
602 res += play_file(qe->chan, qe->parent->sound_minutes);
605 res += ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, (char*) NULL);
606 res += play_file(qe->chan, qe->parent->sound_seconds);
612 /* Set our last_pos indicators */
614 qe->last_pos_said = qe->pos;
616 if (option_verbose > 2)
617 ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n", qe->chan->name, qe->parent->name, qe->pos);
618 res += play_file(qe->chan, qe->parent->sound_thanks);
619 ast_moh_start(qe->chan, qe->moh);
624 static void record_abandoned(struct queue_ent *qe)
626 ast_mutex_lock(&qe->parent->lock);
627 qe->parent->callsabandoned++;
628 ast_mutex_unlock(&qe->parent->lock);
631 static void recalc_holdtime(struct queue_ent *qe)
633 int oldvalue, newvalue;
635 /* Calculate holdtime using a recursive boxcar filter */
636 /* Thanks to SRT for this contribution */
637 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
639 newvalue = time(NULL) - qe->start;
641 ast_mutex_lock(&qe->parent->lock);
642 if (newvalue <= qe->parent->servicelevel)
643 qe->parent->callscompletedinsl++;
644 oldvalue = qe->parent->holdtime;
645 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newvalue) >> 2;
646 ast_mutex_unlock(&qe->parent->lock);
650 static void leave_queue(struct queue_ent *qe)
652 struct ast_call_queue *q;
653 struct queue_ent *cur, *prev = NULL;
658 ast_mutex_lock(&q->lock);
666 /* Take us out of the queue */
667 manager_event(EVENT_FLAG_CALL, "Leave",
668 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\n",
669 qe->chan->name, q->name, q->count);
671 ast_log(LOG_NOTICE, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
673 /* Take us out of the queue */
675 prev->next = cur->next;
679 /* Renumber the people after us in the queue based on a new count */
685 ast_mutex_unlock(&q->lock);
686 if (ast_test_flag(q, QUEUE_FLAG_DEAD) && !q->count) {
687 /* It's dead and nobody is in it, so kill it */
692 static void hanguptree(struct localuser *outgoing, struct ast_channel *exception)
694 /* Hang up a tree of stuff */
695 struct localuser *oo;
697 /* Hangup any existing lines we have open */
698 if (outgoing->chan && (outgoing->chan != exception))
699 ast_hangup(outgoing->chan);
701 outgoing=outgoing->next;
706 static int update_status(struct ast_call_queue *q, struct member *member, int status)
709 /* Since a reload could have taken place, we have to traverse the list to
710 be sure it's still valid */
711 ast_mutex_lock(&q->lock);
715 cur->status = status;
716 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
725 q->name, cur->interface, cur->dynamic ? "dynamic" : "static",
726 cur->penalty, cur->calls, cur->lastcall, cur->status, cur->paused);
732 ast_mutex_unlock(&q->lock);
736 static int update_dial_status(struct ast_call_queue *q, struct member *member, int status)
738 if (status == AST_CAUSE_BUSY)
739 status = AST_DEVICE_BUSY;
740 else if (status == AST_CAUSE_UNREGISTERED)
741 status = AST_DEVICE_UNAVAILABLE;
742 else if (status == AST_CAUSE_NOSUCHDRIVER)
743 status = AST_DEVICE_INVALID;
745 status = AST_DEVICE_UNKNOWN;
746 return update_status(q, member, status);
749 static int compare_weight(struct ast_call_queue *req_q, struct localuser *req_user, char *qname)
751 /* traverse all defined queues which have calls waiting and contain this member
752 return 0 if no other queue has precedence (higher weight) or 1 if found */
753 struct ast_call_queue *q;
755 int found = 0, weight = 0, calls = 0;
758 strncpy(name, req_q->name, sizeof(name) - 1);
759 weight = req_q->weight;
760 calls = req_q->count;
762 ast_mutex_lock(&qlock);
763 for (q = queues; q; q = q->next) { /* spin queues */
764 ast_mutex_lock(&q->lock);
765 if (!strcasecmp(q->name, name)) { /* don't check myself */
766 ast_mutex_unlock(&q->lock);
769 if (q->count && q->members) { /* check only if calls waiting and has members */
770 for (mem = q->members; mem; mem = mem->next) { /* spin members */
771 if (!strcasecmp(mem->interface, req_user->interface)) {
772 ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
773 if (q->weight > weight) {
774 ast_log(LOG_DEBUG, "Queue '%s' (weight %d, calls %d) is preferred over '%s' (weight %d, calls %d)\n", q->name, q->weight, q->count, name, weight, calls);
776 strncpy(qname, q->name, sizeof(qname) - 1);
777 break; /* stop looking for more members */
782 ast_mutex_unlock(&q->lock);
786 ast_mutex_unlock(&qlock);
792 static int ring_entry(struct queue_ent *qe, struct localuser *tmp, int *busies)
800 if (use_weight) { /* fast path */
801 if (compare_weight(qe->parent,tmp,qname)) {
802 ast_verbose(VERBOSE_PREFIX_3 "Attempt (%s: %s) delayed by higher priority queue (%s).\n", qe->parent->name, tmp->interface, qname);
804 ast_cdr_busy(qe->chan->cdr);
810 if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
812 ast_log(LOG_DEBUG, "Wrapuptime not yet expired for %s\n", tmp->interface);
814 ast_cdr_busy(qe->chan->cdr);
820 if (tmp->member->paused) {
822 ast_log(LOG_DEBUG, "%s paused, can't receive call\n", tmp->interface);
824 ast_cdr_busy(qe->chan->cdr);
829 strncpy(tech, tmp->interface, sizeof(tech) - 1);
830 if ((location = strchr(tech, '/')))
835 /* Request the peer */
836 tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
837 if (!tmp->chan) { /* If we can't, just go on to the next call */
839 ast_log(LOG_NOTICE, "Unable to create channel of type '%s' for Queue\n", cur->tech);
842 ast_cdr_busy(qe->chan->cdr);
844 update_dial_status(qe->parent, tmp->member, status);
847 } else if (status != tmp->oldstatus)
848 update_dial_status(qe->parent, tmp->member, status);
850 tmp->chan->appl = "AppQueue";
851 tmp->chan->data = "(Outgoing Line)";
852 tmp->chan->whentohangup = 0;
853 if (tmp->chan->cid.cid_num)
854 free(tmp->chan->cid.cid_num);
855 tmp->chan->cid.cid_num = NULL;
856 if (tmp->chan->cid.cid_name)
857 free(tmp->chan->cid.cid_name);
858 tmp->chan->cid.cid_name = NULL;
859 if (tmp->chan->cid.cid_ani)
860 free(tmp->chan->cid.cid_ani);
861 tmp->chan->cid.cid_ani = NULL;
862 if (qe->chan->cid.cid_num)
863 tmp->chan->cid.cid_num = strdup(qe->chan->cid.cid_num);
864 if (qe->chan->cid.cid_name)
865 tmp->chan->cid.cid_name = strdup(qe->chan->cid.cid_name);
866 if (qe->chan->cid.cid_ani)
867 tmp->chan->cid.cid_ani = strdup(qe->chan->cid.cid_ani);
869 /* Inherit specially named variables from parent channel */
870 ast_channel_inherit_variables(qe->chan, tmp->chan);
872 /* Presense of ADSI CPE on outgoing channel follows ours */
873 tmp->chan->adsicpe = qe->chan->adsicpe;
875 /* Place the call, but don't wait on the answer */
876 res = ast_call(tmp->chan, location, 0);
878 /* Again, keep going even if there's an error */
880 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
881 else if (option_verbose > 2)
882 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface);
883 ast_hangup(tmp->chan);
889 if (ast_test_flag(qe->parent, QUEUE_FLAG_EVENTWHENCALLED)) {
890 manager_event(EVENT_FLAG_AGENT, "AgentCalled",
891 "AgentCalled: %s\r\n"
892 "ChannelCalling: %s\r\n"
894 "CallerIDName: %s\r\n"
898 tmp->interface, qe->chan->name,
899 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
900 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
901 qe->chan->context, qe->chan->exten, qe->chan->priority);
903 if (option_verbose > 2)
904 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface);
909 static int ring_one(struct queue_ent *qe, struct localuser *outgoing, int *busies)
911 struct localuser *cur;
912 struct localuser *best;
918 if (cur->stillgoing && /* Not already done */
919 !cur->chan && /* Isn't already going */
920 (!best || (cur->metric < bestmetric))) { /* We haven't found one yet, or it's better */
921 bestmetric = cur->metric;
927 if (!qe->parent->strategy) {
928 /* Ring everyone who shares this best metric (for ringall) */
931 if (cur->stillgoing && !cur->chan && (cur->metric <= bestmetric)) {
933 ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
934 ring_entry(qe, cur, busies);
939 /* Ring just the best channel */
941 ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric);
942 ring_entry(qe, best, busies);
945 } while (best && !best->chan);
948 ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n");
954 static int store_next(struct queue_ent *qe, struct localuser *outgoing)
956 struct localuser *cur;
957 struct localuser *best;
962 if (cur->stillgoing && /* Not already done */
963 !cur->chan && /* Isn't already going */
964 (!best || (cur->metric < bestmetric))) { /* We haven't found one yet, or it's better */
965 bestmetric = cur->metric;
971 /* Ring just the best channel */
973 ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric);
974 qe->parent->rrpos = best->metric % 1000;
976 /* Just increment rrpos */
977 if (!ast_test_flag(qe->parent, QUEUE_FLAG_WRAPPED)) {
978 /* No more channels, start over */
979 qe->parent->rrpos = 0;
981 /* Prioritize next entry */
985 ast_clear_flag(qe->parent, QUEUE_FLAG_WRAPPED);
989 static int valid_exit(struct queue_ent *qe, char digit)
992 if (ast_strlen_zero(qe->context))
996 if (ast_exists_extension(qe->chan, qe->context, tmp, 1, qe->chan->cid.cid_num)) {
997 strncpy(qe->chan->context, qe->context, sizeof(qe->chan->context) - 1);
998 strncpy(qe->chan->exten, tmp, sizeof(qe->chan->exten) - 1);
999 qe->chan->priority = 0;
1005 #define AST_MAX_WATCHERS 256
1007 #define BUILD_STATS do { \
1014 /* Keep track of important channels */ \
1015 if (o->stillgoing) { \
1018 watchers[pos++] = o->chan; \
1027 static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser *outgoing, int *to, struct ast_flags *flags, char *digit, int prebusies)
1029 char *queue = qe->parent->name;
1030 struct localuser *o;
1034 int sentringing = 0;
1035 int numbusies = prebusies;
1039 struct ast_frame *f;
1040 struct localuser *peer = NULL;
1041 struct ast_channel *watchers[AST_MAX_WATCHERS];
1043 struct ast_channel *winner;
1044 struct ast_channel *in = qe->chan;
1046 while(*to && !peer) {
1048 if ((found < 0) && stillgoing && !qe->parent->strategy) {
1049 /* On "ringall" strategy we only move to the next penalty level
1050 when *all* ringing phones are done in the current penalty level */
1051 ring_one(qe, outgoing, &numbusies);
1055 if (numlines == (numbusies + numnochan)) {
1056 ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
1058 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan);
1063 winner = ast_waitfor_n(watchers, pos, to);
1066 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
1068 if (option_verbose > 2)
1069 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
1071 ast_copy_flags(flags, o, QUEUE_FLAG_REDIR_IN | QUEUE_FLAG_REDIR_OUT | QUEUE_FLAG_DISCON_IN | QUEUE_FLAG_DISCON_OUT);
1073 } else if (o->chan && (o->chan == winner)) {
1074 if (!ast_strlen_zero(o->chan->call_forward)) {
1075 char tmpchan[256]="";
1078 strncpy(tmpchan, o->chan->call_forward, sizeof(tmpchan) - 1);
1079 if ((stuff = strchr(tmpchan, '/'))) {
1084 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
1088 /* Before processing channel, go ahead and check for forwarding */
1089 if (option_verbose > 2)
1090 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
1091 /* Setup parameters */
1092 o->chan = ast_request(tech, in->nativeformats, stuff, &status);
1093 if (status != o->oldstatus)
1094 update_dial_status(qe->parent, o->member, status);
1096 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
1100 if (o->chan->cid.cid_num)
1101 free(o->chan->cid.cid_num);
1102 o->chan->cid.cid_num = NULL;
1103 if (o->chan->cid.cid_name)
1104 free(o->chan->cid.cid_name);
1105 o->chan->cid.cid_name = NULL;
1107 if (in->cid.cid_num) {
1108 o->chan->cid.cid_num = strdup(in->cid.cid_num);
1109 if (!o->chan->cid.cid_num)
1110 ast_log(LOG_WARNING, "Out of memory\n");
1112 if (in->cid.cid_name) {
1113 o->chan->cid.cid_name = strdup(in->cid.cid_name);
1114 if (!o->chan->cid.cid_name)
1115 ast_log(LOG_WARNING, "Out of memory\n");
1117 strncpy(o->chan->accountcode, in->accountcode, sizeof(o->chan->accountcode) - 1);
1118 o->chan->cdrflags = in->cdrflags;
1120 if (in->cid.cid_ani) {
1121 if (o->chan->cid.cid_ani)
1122 free(o->chan->cid.cid_ani);
1123 o->chan->cid.cid_ani = malloc(strlen(in->cid.cid_ani) + 1);
1124 if (o->chan->cid.cid_ani)
1125 strncpy(o->chan->cid.cid_ani, in->cid.cid_ani, strlen(in->cid.cid_ani) + 1);
1127 ast_log(LOG_WARNING, "Out of memory\n");
1129 if (o->chan->cid.cid_rdnis)
1130 free(o->chan->cid.cid_rdnis);
1131 if (!ast_strlen_zero(in->macroexten))
1132 o->chan->cid.cid_rdnis = strdup(in->macroexten);
1134 o->chan->cid.cid_rdnis = strdup(in->exten);
1135 if (ast_call(o->chan, tmpchan, 0)) {
1136 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
1138 ast_hangup(o->chan);
1143 /* Hangup the original channel now, in case we needed it */
1147 f = ast_read(winner);
1149 if (f->frametype == AST_FRAME_CONTROL) {
1150 switch(f->subclass) {
1151 case AST_CONTROL_ANSWER:
1152 /* This is our guy if someone answered. */
1154 ast_copy_flags(flags, o, QUEUE_FLAG_REDIR_IN | QUEUE_FLAG_REDIR_OUT | QUEUE_FLAG_DISCON_IN | QUEUE_FLAG_DISCON_OUT);
1155 if (option_verbose > 2)
1156 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
1158 ast_copy_flags(flags, o, QUEUE_FLAG_REDIR_IN & QUEUE_FLAG_REDIR_OUT & QUEUE_FLAG_DISCON_IN & QUEUE_FLAG_DISCON_OUT);
1161 case AST_CONTROL_BUSY:
1162 if (option_verbose > 2)
1163 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
1166 ast_cdr_busy(in->cdr);
1167 ast_hangup(o->chan);
1169 if (qe->parent->strategy) {
1170 if (ast_test_flag(qe->parent, QUEUE_FLAG_TIMEOUTRESTART))
1172 ring_one(qe, outgoing, &numbusies);
1176 case AST_CONTROL_CONGESTION:
1177 if (option_verbose > 2)
1178 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
1181 ast_cdr_busy(in->cdr);
1182 ast_hangup(o->chan);
1184 if (qe->parent->strategy) {
1185 if (ast_test_flag(qe->parent, QUEUE_FLAG_TIMEOUTRESTART))
1187 ring_one(qe, outgoing, &numbusies);
1191 case AST_CONTROL_RINGING:
1192 if (option_verbose > 2)
1193 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
1196 ast_indicate(in, AST_CONTROL_RINGING);
1201 case AST_CONTROL_OFFHOOK:
1202 /* Ignore going off hook */
1205 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
1211 ast_hangup(o->chan);
1213 if (qe->parent->strategy) {
1214 if (ast_test_flag(qe->parent, QUEUE_FLAG_TIMEOUTRESTART))
1216 ring_one(qe, outgoing, &numbusies);
1225 if (f && (f->frametype != AST_FRAME_VOICE))
1226 printf("Frame type: %d, %d\n", f->frametype, f->subclass);
1227 else if (!f || (f->frametype != AST_FRAME_VOICE))
1228 printf("Hangup received on %s\n", in->name);
1230 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
1235 if (f && (f->frametype == AST_FRAME_DTMF) && ast_test_flag(flags, QUEUE_FLAG_DISCON_OUT) && (f->subclass == '*')) {
1236 if (option_verbose > 3)
1237 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
1241 if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass != '*') && valid_exit(qe, f->subclass)) {
1242 if (option_verbose > 3)
1243 ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c", f->subclass);
1249 if (!*to && (option_verbose > 2))
1250 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
1257 static int is_our_turn(struct queue_ent *qe)
1259 struct queue_ent *ch;
1262 /* Atomically read the parent head -- does not need a lock */
1263 ch = qe->parent->head;
1264 /* If we are now at the top of the head, break out */
1267 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
1271 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
1277 static int wait_our_turn(struct queue_ent *qe, int ringing)
1281 /* This is the holding pen for callers 2 through maxlen */
1283 if (is_our_turn(qe))
1286 /* If we have timed out, break out */
1287 if (qe->expire && (time(NULL) > qe->expire))
1290 /* leave the queue if no agents, if enabled */
1291 if (ast_test_flag(qe->parent, QUEUE_FLAG_LEAVEWHENEMPTY) && has_no_members(qe->parent)) {
1296 /* Make a position announcement, if enabled */
1297 if (qe->parent->announcefrequency && !ringing)
1300 /* Wait a second before checking again */
1301 res = ast_waitfordigit(qe->chan, RECHECK * 1000);
1308 static int update_queue(struct ast_call_queue *q, struct member *member)
1311 /* Since a reload could have taken place, we have to traverse the list to
1312 be sure it's still valid */
1313 ast_mutex_lock(&q->lock);
1316 if (member == cur) {
1317 time(&cur->lastcall);
1323 q->callscompleted++;
1324 ast_mutex_unlock(&q->lock);
1328 static int calc_metric(struct ast_call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct localuser *tmp)
1330 switch (q->strategy) {
1331 case QUEUE_STRATEGY_RINGALL:
1332 /* Everyone equal, except for penalty */
1333 tmp->metric = mem->penalty * 1000000;
1335 case QUEUE_STRATEGY_ROUNDROBIN:
1337 if (!ast_test_flag(q, QUEUE_FLAG_WRAPPED)) {
1338 /* No more channels, start over */
1341 /* Prioritize next entry */
1344 ast_clear_flag(q, QUEUE_FLAG_WRAPPED);
1347 case QUEUE_STRATEGY_RRMEMORY:
1348 if (pos < q->rrpos) {
1349 tmp->metric = 1000 + pos;
1351 if (pos > q->rrpos) {
1352 /* Indicate there is another priority */
1353 ast_set_flag(q, QUEUE_FLAG_WRAPPED);
1357 tmp->metric += mem->penalty * 1000000;
1359 case QUEUE_STRATEGY_RANDOM:
1360 tmp->metric = rand() % 1000;
1361 tmp->metric += mem->penalty * 1000000;
1363 case QUEUE_STRATEGY_FEWESTCALLS:
1364 tmp->metric = mem->calls;
1365 tmp->metric += mem->penalty * 1000000;
1367 case QUEUE_STRATEGY_LEASTRECENT:
1371 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
1372 tmp->metric += mem->penalty * 1000000;
1375 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
1381 static int try_calling(struct queue_ent *qe, char *ooptions, char *announceoverride, char *url, int *go_on)
1384 struct localuser *outgoing=NULL, *tmp = NULL;
1386 struct ast_flags flags;
1387 char restofit[AST_MAX_EXTENSION];
1388 char oldexten[AST_MAX_EXTENSION]="";
1389 char oldcontext[AST_MAX_EXTENSION]="";
1390 char queuename[256]="";
1393 char *monitorfilename;
1394 struct ast_channel *peer;
1395 struct ast_channel *which;
1396 struct localuser *lpeer;
1397 struct member *member;
1398 int res = 0, bridge = 0;
1402 char *announce = NULL;
1406 struct ast_bridge_config config;
1407 /* Hold the lock while we setup the outgoing calls */
1408 ast_mutex_lock(&qe->parent->lock);
1410 ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n",
1412 strncpy(queuename, qe->parent->name, sizeof(queuename) - 1);
1414 cur = qe->parent->members;
1415 if (!ast_strlen_zero(qe->announce))
1416 announce = qe->announce;
1417 if (announceoverride && !ast_strlen_zero(announceoverride))
1418 announce = announceoverride;
1420 /* Get a technology/[device:]number pair */
1421 tmp = malloc(sizeof(struct localuser));
1423 ast_mutex_unlock(&qe->parent->lock);
1424 ast_log(LOG_WARNING, "Out of memory\n");
1427 memset(tmp, 0, sizeof(struct localuser));
1428 tmp->stillgoing = -1;
1430 for (; options && *options; options++)
1433 ast_set_flag(tmp, QUEUE_FLAG_REDIR_IN);
1436 ast_set_flag(tmp, QUEUE_FLAG_REDIR_OUT);
1439 ast_set_flag(tmp, QUEUE_FLAG_RINGBACKONLY);
1442 ast_set_flag(tmp, QUEUE_FLAG_MUSICONHOLD);
1445 ast_set_flag(tmp, QUEUE_FLAG_DATAQUALITY);
1448 ast_set_flag(tmp, QUEUE_FLAG_DISCON_IN);
1451 ast_set_flag(tmp, QUEUE_FLAG_DISCON_OUT);
1454 if ((now - qe->start >= qe->parent->timeout))
1460 ast_log(LOG_DEBUG, "Queue with URL=%s_\n", url);
1462 ast_log(LOG_DEBUG, "Simple queue (no URL)\n");
1465 tmp->member = cur; /* Never directly dereference! Could change on reload */
1466 tmp->oldstatus = cur->status;
1467 tmp->lastcall = cur->lastcall;
1468 strncpy(tmp->interface, cur->interface, sizeof(tmp->interface)-1);
1469 /* If we're dialing by extension, look at the extension to know what to dial */
1470 if ((newnum = strstr(tmp->interface, "/BYEXTENSION"))) {
1472 strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit) - 1);
1473 snprintf(newnum, sizeof(tmp->interface) - (newnum - tmp->interface), "%s%s", qe->chan->exten, restofit);
1475 ast_log(LOG_DEBUG, "Dialing by extension %s\n", tmp->interface);
1477 /* Special case: If we ring everyone, go ahead and ring them, otherwise
1478 just calculate their metric for the appropriate strategy */
1479 calc_metric(qe->parent, cur, x++, qe, tmp);
1480 /* Put them in the list of outgoing thingies... We're ready now.
1481 XXX If we're forcibly removed, these outgoing calls won't get
1483 tmp->next = outgoing;
1485 /* If this line is up, don't try anybody else */
1486 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
1491 if (qe->parent->timeout)
1492 to = qe->parent->timeout * 1000;
1495 ring_one(qe, outgoing, &numbusies);
1496 ast_mutex_unlock(&qe->parent->lock);
1497 lpeer = wait_for_answer(qe, outgoing, &to, &flags, &digit, numbusies);
1498 ast_mutex_lock(&qe->parent->lock);
1499 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
1500 store_next(qe, outgoing);
1502 ast_mutex_unlock(&qe->parent->lock);
1509 /* Musta gotten hung up */
1510 record_abandoned(qe);
1513 if (digit && valid_exit(qe, digit))
1516 /* Nobody answered, next please? */
1520 ast_log(LOG_DEBUG, "%s: Nobody answered.\n", qe->chan->name);
1524 /* Ah ha! Someone answered within the desired timeframe. Of course after this
1525 we will always return with -1 so that it is hung up properly after the
1528 if (!strcmp(qe->chan->type,"Zap")) {
1529 zapx = !ast_test_flag(tmp, QUEUE_FLAG_DATAQUALITY);
1530 ast_channel_setoption(qe->chan,AST_OPTION_TONE_VERIFY,&zapx,sizeof(char),0);
1532 if (!strcmp(peer->type,"Zap")) {
1533 zapx = !ast_test_flag(tmp, QUEUE_FLAG_DATAQUALITY);
1534 ast_channel_setoption(peer,AST_OPTION_TONE_VERIFY,&zapx,sizeof(char),0);
1536 /* Update parameters for the queue */
1537 recalc_holdtime(qe);
1538 member = lpeer->member;
1539 hanguptree(outgoing, peer);
1541 if (announce || ast_test_flag(qe->parent, QUEUE_FLAG_REPORTHOLDTIME) || qe->parent->memberdelay) {
1543 res2 = ast_autoservice_start(qe->chan);
1545 if (qe->parent->memberdelay) {
1546 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
1547 res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
1549 if (!res2 && announce) {
1550 if (play_file(peer, announce))
1551 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", announce);
1553 if (!res2 && ast_test_flag(qe->parent, QUEUE_FLAG_REPORTHOLDTIME)) {
1554 if (!play_file(peer, qe->parent->sound_reporthold)) {
1559 holdtime = abs((now - qe->start) / 60);
1561 play_file(peer, qe->parent->sound_lessthan);
1562 ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL);
1564 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
1565 play_file(peer, qe->parent->sound_minutes);
1569 res2 |= ast_autoservice_stop(qe->chan);
1570 if (peer->_softhangup) {
1571 /* Agent must have hung up */
1572 ast_log(LOG_WARNING, "Agent on %s hungup on the customer. They're going to be pissed.\n", peer->name);
1573 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "AGENTDUMP", "%s", "");
1574 if (ast_test_flag(qe->parent, QUEUE_FLAG_EVENTWHENCALLED)) {
1575 manager_event(EVENT_FLAG_AGENT, "AgentDump",
1580 queuename, qe->chan->uniqueid, peer->name, member->interface);
1585 /* Caller must have hung up just before being connected*/
1586 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
1587 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
1588 record_abandoned(qe);
1593 /* Stop music on hold */
1594 ast_moh_stop(qe->chan);
1595 /* If appropriate, log that we have a destination channel */
1597 ast_cdr_setdestchan(qe->chan->cdr, peer->name);
1598 /* Make sure channels are compatible */
1599 res = ast_channel_make_compatible(qe->chan, peer);
1601 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "SYSCOMPAT", "%s", "");
1602 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
1606 /* Begin Monitoring */
1607 if (qe->parent->monfmt && *qe->parent->monfmt) {
1608 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
1609 if(pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper( qe->chan, "MONITOR_EXEC_ARGS"))
1613 if(monitorfilename) {
1614 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 );
1616 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
1618 if(ast_test_flag(qe->parent, QUEUE_FLAG_MONJOIN)) {
1619 ast_monitor_setjoinfiles(which, 1);
1622 /* Drop out of the queue at this point, to prepare for next caller */
1624 if( url && !ast_strlen_zero(url) && ast_channel_supports_html(peer) ) {
1626 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
1627 ast_channel_sendurl( peer, url );
1629 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "CONNECT", "%ld", (long)time(NULL) - qe->start);
1630 if (ast_test_flag(qe->parent, QUEUE_FLAG_EVENTWHENCALLED)) {
1631 manager_event(EVENT_FLAG_AGENT, "AgentConnect",
1636 "Holdtime: %ld\r\n",
1637 queuename, qe->chan->uniqueid, peer->name, member->interface, (long)time(NULL) - qe->start);
1639 strncpy(oldcontext, qe->chan->context, sizeof(oldcontext) - 1);
1640 strncpy(oldexten, qe->chan->exten, sizeof(oldexten) - 1);
1643 memset(&config,0,sizeof(struct ast_bridge_config));
1645 if (ast_test_flag(&flags, QUEUE_FLAG_REDIR_IN))
1646 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
1647 if (ast_test_flag(&flags, QUEUE_FLAG_REDIR_OUT))
1648 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
1649 if (ast_test_flag(&flags, QUEUE_FLAG_DISCON_IN))
1650 ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
1651 if (ast_test_flag(&flags, QUEUE_FLAG_DISCON_OUT))
1652 ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
1653 bridge = ast_bridge_call(qe->chan,peer,&config);
1655 if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
1656 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "TRANSFER", "%s|%s", qe->chan->exten, qe->chan->context);
1657 } else if (qe->chan->_softhangup) {
1658 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETECALLER", "%ld|%ld", (long)(callstart - qe->start), (long)(time(NULL) - callstart));
1659 if (ast_test_flag(qe->parent, QUEUE_FLAG_EVENTWHENCALLED)) {
1660 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
1667 "Reason: caller\r\n",
1668 queuename, qe->chan->uniqueid, peer->name, member->interface, (long)(callstart - qe->start), (long)(time(NULL) - callstart));
1671 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETEAGENT", "%ld|%ld", (long)(callstart - qe->start), (long)(time(NULL) - callstart));
1672 if (ast_test_flag(qe->parent, QUEUE_FLAG_EVENTWHENCALLED)) {
1673 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
1679 "Reason: agent\r\n",
1680 queuename, qe->chan->uniqueid, peer->name, (long)(callstart - qe->start), (long)(time(NULL) - callstart));
1685 if(bridge != AST_PBX_NO_HANGUP_PEER)
1687 update_queue(qe->parent, member);
1689 res = 1; /* JDG: bridge successfull, leave app_queue */
1691 res = bridge; /* bridge error, stay in the queue */
1694 hanguptree(outgoing, NULL);
1698 static int wait_a_bit(struct queue_ent *qe)
1700 /* Don't need to hold the lock while we setup the outgoing calls */
1701 int retrywait = qe->parent->retry * 1000;
1702 return ast_waitfordigit(qe->chan, retrywait);
1705 /* [PHM 06/26/03] */
1707 static struct member * interface_exists(struct ast_call_queue *q, char *interface)
1712 for (mem = q->members; mem; mem = mem->next)
1713 if (!strcmp(interface, mem->interface))
1720 static struct member *create_queue_node(char *interface, int penalty, int paused)
1724 /* Add a new member */
1726 cur = malloc(sizeof(struct member));
1729 memset(cur, 0, sizeof(struct member));
1730 cur->penalty = penalty;
1731 cur->paused = paused;
1732 strncpy(cur->interface, interface, sizeof(cur->interface) - 1);
1733 if (!strchr(cur->interface, '/'))
1734 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
1735 cur->status = ast_device_state(interface);
1741 /* Dump all members in a specific queue to the databse
1743 * <pm_family>/<queuename> = <interface>;<penalty>;<paused>[|...]
1746 static void dump_queue_members(struct ast_call_queue *pm_queue)
1748 struct member *cur_member;
1749 char value[PM_MAX_LEN];
1753 memset(value, 0, sizeof(value));
1758 for (cur_member = pm_queue->members; cur_member; cur_member = cur_member->next) {
1759 if (!cur_member->dynamic)
1762 res = snprintf(value + value_len, sizeof(value) - value_len, "%s;%d;%d%s",
1763 cur_member->interface, cur_member->penalty, cur_member->paused,
1764 cur_member->next ? "|" : "");
1765 if (res != strlen(value + value_len)) {
1766 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
1772 if (value_len && !cur_member) {
1773 if (ast_db_put(pm_family, pm_queue->name, value))
1774 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
1776 /* Delete the entry if the queue is empty or there is an error */
1777 ast_db_del(pm_family, pm_queue->name);
1780 static int remove_from_queue(char *queuename, char *interface)
1782 struct ast_call_queue *q;
1783 struct member *last_member, *look;
1784 int res = RES_NOSUCHQUEUE;
1786 ast_mutex_lock(&qlock);
1787 for (q = queues ; q ; q = q->next) {
1788 ast_mutex_lock(&q->lock);
1789 if (!strcmp(q->name, queuename)) {
1790 if ((last_member = interface_exists(q, interface))) {
1791 if ((look = q->members) == last_member) {
1792 q->members = last_member->next;
1794 while (look != NULL) {
1795 if (look->next == last_member) {
1796 look->next = last_member->next;
1803 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
1806 q->name, last_member->interface);
1809 if (queue_persistent_members)
1810 dump_queue_members(q);
1816 ast_mutex_unlock(&q->lock);
1819 ast_mutex_unlock(&q->lock);
1821 ast_mutex_unlock(&qlock);
1825 static int add_to_queue(char *queuename, char *interface, int penalty, int paused, int dump)
1827 struct ast_call_queue *q;
1828 struct member *new_member;
1829 int res = RES_NOSUCHQUEUE;
1831 ast_mutex_lock(&qlock);
1832 for (q = queues ; q ; q = q->next) {
1833 ast_mutex_lock(&q->lock);
1834 if (!strcmp(q->name, queuename)) {
1835 if (interface_exists(q, interface) == NULL) {
1836 new_member = create_queue_node(interface, penalty, paused);
1838 if (new_member != NULL) {
1839 new_member->dynamic = 1;
1840 new_member->next = q->members;
1841 q->members = new_member;
1842 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
1845 "Membership: %s\r\n"
1847 "CallsTaken: %d\r\n"
1851 q->name, new_member->interface, new_member->dynamic ? "dynamic" : "static",
1852 new_member->penalty, new_member->calls, new_member->lastcall, new_member->status, new_member->paused);
1855 dump_queue_members(q);
1859 res = RES_OUTOFMEMORY;
1864 ast_mutex_unlock(&q->lock);
1867 ast_mutex_unlock(&q->lock);
1869 ast_mutex_unlock(&qlock);
1873 static int set_member_paused(char *queuename, char *interface, int paused)
1876 struct ast_call_queue *q;
1879 /* Special event for when all queues are paused - individual events still generated */
1881 if (ast_strlen_zero(queuename))
1882 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
1884 ast_mutex_lock(&qlock);
1885 for (q = queues ; q ; q = q->next) {
1886 ast_mutex_lock(&q->lock);
1887 if (ast_strlen_zero(queuename) || !strcmp(q->name, queuename)) {
1888 if ((mem = interface_exists(q, interface))) {
1890 if (mem->paused == paused)
1891 ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
1892 mem->paused = paused;
1894 if (queue_persistent_members)
1895 dump_queue_members(q);
1897 ast_queue_log(q->name, "NONE", interface, (paused ? "PAUSE" : "UNPAUSE"), "%s", "");
1899 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
1903 q->name, mem->interface, paused);
1906 ast_mutex_unlock(&q->lock);
1908 ast_mutex_unlock(&qlock);
1911 return RESULT_SUCCESS;
1913 return RESULT_FAILURE;
1916 /* Reload dynamic queue members persisted into the astdb */
1917 static void reload_queue_members(void)
1927 struct ast_db_entry *db_tree;
1928 struct ast_db_entry *entry;
1929 struct ast_call_queue *cur_queue;
1930 char queue_data[PM_MAX_LEN];
1932 ast_mutex_lock(&qlock);
1934 /* Each key in 'pm_family' is the name of a queue */
1935 db_tree = ast_db_gettree(pm_family, NULL);
1936 for (entry = db_tree; entry; entry = entry->next) {
1938 queue_name = entry->key + strlen(pm_family) + 2;
1942 ast_mutex_lock(&cur_queue->lock);
1943 if (!strcmp(queue_name, cur_queue->name))
1945 ast_mutex_unlock(&cur_queue->lock);
1946 cur_queue = cur_queue->next;
1950 /* If the queue no longer exists, remove it from the
1952 ast_db_del(pm_family, queue_name);
1955 ast_mutex_unlock(&cur_queue->lock);
1957 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN))
1960 cur_ptr = queue_data;
1961 while ((member = strsep(&cur_ptr, "|"))) {
1962 if (ast_strlen_zero(member))
1965 interface = strsep(&member, ";");
1966 penalty_tok = strsep(&member, ";");
1967 paused_tok = strsep(&member, ";");
1970 ast_log(LOG_WARNING, "Error parsing persisent member string for '%s' (penalty)\n", queue_name);
1973 penalty = strtol(penalty_tok, NULL, 10);
1974 if (errno == ERANGE) {
1975 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
1980 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
1983 paused = strtol(paused_tok, NULL, 10);
1984 if ((errno == ERANGE) || paused < 0 || paused > 1) {
1985 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
1990 ast_log(LOG_DEBUG, "Reload Members: Queue: %s Member: %s Penalty: %d Paused: %d\n", queue_name, interface, penalty, paused);
1992 if (add_to_queue(queue_name, interface, penalty, paused, 0) == RES_OUTOFMEMORY) {
1993 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
1999 ast_mutex_unlock(&qlock);
2001 ast_log(LOG_NOTICE, "Queue members sucessfully reloaded from database.\n");
2002 ast_db_freetree(db_tree);
2006 static int pqm_exec(struct ast_channel *chan, void *data)
2008 struct localuser *u;
2009 char *queuename, *interface;
2012 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface])\n");
2016 queuename = ast_strdupa((char *)data);
2018 ast_log(LOG_ERROR, "Out of memory\n");
2022 interface = strchr(queuename, '|');
2024 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface])\n");
2033 if (set_member_paused(queuename, interface, 1)) {
2034 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", interface);
2035 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2036 chan->priority += 100;
2037 LOCAL_USER_REMOVE(u);
2043 LOCAL_USER_REMOVE(u);
2048 static int upqm_exec(struct ast_channel *chan, void *data)
2050 struct localuser *u;
2051 char *queuename, *interface;
2054 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface])\n");
2058 queuename = ast_strdupa((char *)data);
2060 ast_log(LOG_ERROR, "Out of memory\n");
2064 interface = strchr(queuename, '|');
2066 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface])\n");
2075 if (set_member_paused(queuename, interface, 0)) {
2076 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", interface);
2077 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2078 chan->priority += 100;
2079 LOCAL_USER_REMOVE(u);
2085 LOCAL_USER_REMOVE(u);
2090 static int rqm_exec(struct ast_channel *chan, void *data)
2093 struct localuser *u;
2094 char *info, *queuename;
2095 char tmpchan[256]="";
2096 char *interface = NULL;
2099 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface])\n");
2103 info = ast_strdupa((char *)data);
2105 ast_log(LOG_ERROR, "Out of memory\n");
2113 interface = strchr(queuename, '|');
2119 strncpy(tmpchan, chan->name, sizeof(tmpchan) - 1);
2120 interface = strrchr(tmpchan, '-');
2123 interface = tmpchan;
2127 switch (remove_from_queue(queuename, interface)) {
2129 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", interface, queuename);
2133 ast_log(LOG_WARNING, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
2134 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2135 chan->priority += 100;
2139 case RES_NOSUCHQUEUE:
2140 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", queuename);
2143 case RES_OUTOFMEMORY:
2144 ast_log(LOG_ERROR, "Out of memory\n");
2148 LOCAL_USER_REMOVE(u);
2152 static int aqm_exec(struct ast_channel *chan, void *data)
2155 struct localuser *u;
2158 char tmpchan[512]="";
2159 char *interface=NULL;
2160 char *penaltys=NULL;
2164 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface][|penalty]])\n");
2168 info = ast_strdupa((char *)data);
2170 ast_log(LOG_ERROR, "Out of memory\n");
2177 interface = strchr(queuename, '|');
2183 penaltys = strchr(interface, '|');
2189 if (!interface || ast_strlen_zero(interface)) {
2190 strncpy(tmpchan, chan->name, sizeof(tmpchan) - 1);
2191 interface = strrchr(tmpchan, '-');
2194 interface = tmpchan;
2196 if (penaltys && !ast_strlen_zero(penaltys)) {
2197 if ((sscanf(penaltys, "%d", &penalty) != 1) || penalty < 0) {
2198 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", penaltys);
2204 switch (add_to_queue(queuename, interface, penalty, 0, queue_persistent_members)) {
2206 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", interface, queuename);
2210 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
2211 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2212 chan->priority += 100;
2216 case RES_NOSUCHQUEUE:
2217 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", queuename);
2220 case RES_OUTOFMEMORY:
2221 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", interface, queuename);
2225 LOCAL_USER_REMOVE(u);
2229 static int queue_exec(struct ast_channel *chan, void *data)
2233 struct localuser *u;
2236 char *info_ptr = info;
2237 char *options = NULL;
2239 char *announceoverride = NULL;
2240 char *user_priority;
2242 char *queuetimeoutstr = NULL;
2244 /* whether to exit Queue application after the timeout hits */
2247 /* Our queue entry */
2248 struct queue_ent qe;
2250 if (!data || ast_strlen_zero(data)) {
2251 ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL][|announceoverride][|timeout]]\n");
2257 /* Setup our queue entry */
2258 memset(&qe, 0, sizeof(qe));
2259 qe.start = time(NULL);
2261 /* Parse our arguments XXX Check for failure XXX */
2262 strncpy(info, (char *) data, sizeof(info) - 1);
2263 queuename = strsep(&info_ptr, "|");
2264 options = strsep(&info_ptr, "|");
2265 url = strsep(&info_ptr, "|");
2266 announceoverride = strsep(&info_ptr, "|");
2267 queuetimeoutstr = info_ptr;
2269 /* set the expire time based on the supplied timeout; */
2270 if (queuetimeoutstr)
2271 qe.expire = qe.start + atoi(queuetimeoutstr);
2275 /* Get the priority from the variable ${QUEUE_PRIO} */
2276 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
2277 if (user_priority) {
2278 if (sscanf(user_priority, "%d", &prio) == 1) {
2280 ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
2283 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
2284 user_priority, chan->name);
2288 if (option_debug > 2)
2289 ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n");
2294 if (strchr(options, 'r')) {
2300 ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
2301 queuename, options, url, announceoverride, (long)qe.expire, (int)prio);
2304 qe.prio = (int)prio;
2305 qe.last_pos_said = 0;
2307 if (!join_queue(queuename, &qe)) {
2308 ast_queue_log(queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", url ? url : "", chan->cid.cid_num ? chan->cid.cid_num : "");
2309 /* Start music on hold */
2312 ast_indicate(chan, AST_CONTROL_RINGING);
2314 ast_moh_start(chan, qe.moh);
2317 /* This is the wait loop for callers 2 through maxlen */
2319 res = wait_our_turn(&qe, ringing);
2320 /* If they hungup, return immediately */
2322 /* Record this abandoned call */
2323 record_abandoned(&qe);
2324 ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
2325 if (option_verbose > 2) {
2326 ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s while waiting their turn\n", queuename);
2333 if (valid_exit(&qe, res)) {
2334 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
2339 int makeannouncement = 0;
2341 /* This is the wait loop for the head caller*/
2342 /* To exit, they may get their call answered; */
2343 /* they may dial a digit from the queue context; */
2344 /* or, they may timeout. */
2346 /* Leave if we have exceeded our queuetimeout */
2347 if (qe.expire && (time(NULL) > qe.expire)) {
2352 if (makeannouncement) {
2353 /* Make a position announcement, if enabled */
2354 if (qe.parent->announcefrequency && !ringing)
2357 makeannouncement = 1;
2359 /* Try calling all queue members for 'timeout' seconds */
2360 res = try_calling(&qe, options, announceoverride, url, &go_on);
2364 ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
2366 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
2370 /* leave the queue if no agents, if enabled */
2371 if (ast_test_flag(qe.parent, QUEUE_FLAG_LEAVEWHENEMPTY) && has_no_members(qe.parent)) {
2376 /* Leave if we have exceeded our queuetimeout */
2377 if (qe.expire && (time(NULL) > qe.expire)) {
2382 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
2383 res = wait_a_bit(&qe);
2385 ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
2386 if (option_verbose > 2) {
2387 ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s when they almost made it\n", queuename);
2392 if (res && valid_exit(&qe, res)) {
2393 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
2396 /* exit after 'timeout' cycle if 'n' option enabled */
2398 if (option_verbose > 2) {
2399 ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n");
2402 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
2406 /* Since this is a priority queue and
2407 * it is not sure that we are still at the head
2408 * of the queue, go and check for our turn again.
2410 if (!is_our_turn(&qe)) {
2412 ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n",
2418 /* Don't allow return code > 0 */
2419 if (res >= 0 && res != AST_PBX_KEEPALIVE) {
2422 ast_indicate(chan, -1);
2426 ast_stopstream(chan);
2430 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", queuename);
2433 LOCAL_USER_REMOVE(u);
2437 static void reload_queues(void)
2439 struct ast_call_queue *q, *ql, *qn;
2440 struct ast_config *cfg;
2442 struct ast_variable *var;
2443 struct member *prev, *cur;
2445 char *general_val = NULL;
2447 cfg = ast_config_load("queues.conf");
2449 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
2452 ast_mutex_lock(&qlock);
2454 /* Mark all queues as dead for the moment */
2457 ast_set_flag(q, QUEUE_FLAG_DEAD);
2460 /* Chug through config file */
2461 cat = ast_category_browse(cfg, NULL);
2463 if (strcasecmp(cat, "general")) { /* Define queue */
2464 /* Look for an existing one */
2467 if (!strcmp(q->name, cat))
2473 q = malloc(sizeof(struct ast_call_queue));
2476 memset(q, 0, sizeof(struct ast_call_queue));
2477 ast_mutex_init(&q->lock);
2478 strncpy(q->name, cat, sizeof(q->name) - 1);
2485 ast_mutex_lock(&q->lock);
2486 /* Re-initialize the queue */
2487 ast_clear_flag(q, QUEUE_FLAG_DEAD);
2488 q->retry = DEFAULT_RETRY;
2491 q->announcefrequency = 0;
2492 q->announceholdtime = 0;
2493 q->roundingseconds = 0; /* Default - don't announce seconds */
2495 q->callscompleted = 0;
2496 q->callsabandoned = 0;
2497 q->callscompletedinsl = 0;
2498 q->servicelevel = 0;
2502 q->announce[0] = '\0';
2503 q->context[0] = '\0';
2504 q->monfmt[0] = '\0';
2505 strncpy(q->sound_next, "queue-youarenext", sizeof(q->sound_next) - 1);
2506 strncpy(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare) - 1);
2507 strncpy(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls) - 1);
2508 strncpy(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime) - 1);
2509 strncpy(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes) - 1);
2510 strncpy(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds) - 1);
2511 strncpy(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks) - 1);
2512 strncpy(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan) - 1);
2513 strncpy(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold) - 1);
2516 /* find the end of any dynamic members */
2520 var = ast_variable_browse(cfg, cat);
2522 if (!strcasecmp(var->name, "member")) {
2523 /* Add a new member */
2524 cur = malloc(sizeof(struct member));
2526 memset(cur, 0, sizeof(struct member));
2527 strncpy(cur->interface, var->value, sizeof(cur->interface) - 1);
2528 if ((tmp = strchr(cur->interface, ','))) {
2531 cur->penalty = atoi(tmp);
2532 if (cur->penalty < 0)
2535 if (!strchr(cur->interface, '/'))
2536 ast_log(LOG_WARNING, "No location at line %d of queue.conf\n", var->lineno);
2543 } else if (!strcasecmp(var->name, "music") || !strcasecmp(var->name, "musiconhold")) {
2544 strncpy(q->moh, var->value, sizeof(q->moh) - 1);
2545 } else if (!strcasecmp(var->name, "announce")) {
2546 strncpy(q->announce, var->value, sizeof(q->announce) - 1);
2547 } else if (!strcasecmp(var->name, "context")) {
2548 strncpy(q->context, var->value, sizeof(q->context) - 1);
2549 } else if (!strcasecmp(var->name, "timeout")) {
2550 q->timeout = atoi(var->value);
2551 } else if (!strcasecmp(var->name, "monitor-join")) {
2552 ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_MONJOIN);
2553 } else if (!strcasecmp(var->name, "monitor-format")) {
2554 strncpy(q->monfmt, var->value, sizeof(q->monfmt) - 1);
2555 } else if (!strcasecmp(var->name, "queue-youarenext")) {
2556 strncpy(q->sound_next, var->value, sizeof(q->sound_next) - 1);
2557 } else if (!strcasecmp(var->name, "queue-thereare")) {
2558 strncpy(q->sound_thereare, var->value, sizeof(q->sound_thereare) - 1);
2559 } else if (!strcasecmp(var->name, "queue-callswaiting")) {
2560 strncpy(q->sound_calls, var->value, sizeof(q->sound_calls) - 1);
2561 } else if (!strcasecmp(var->name, "queue-holdtime")) {
2562 strncpy(q->sound_holdtime, var->value, sizeof(q->sound_holdtime) - 1);
2563 } else if (!strcasecmp(var->name, "queue-minutes")) {
2564 strncpy(q->sound_minutes, var->value, sizeof(q->sound_minutes) - 1);
2565 } else if (!strcasecmp(var->name, "queue-seconds")) {
2566 strncpy(q->sound_seconds, var->value, sizeof(q->sound_seconds) - 1);
2567 } else if (!strcasecmp(var->name, "queue-lessthan")) {
2568 strncpy(q->sound_lessthan, var->value, sizeof(q->sound_lessthan) - 1);
2569 } else if (!strcasecmp(var->name, "queue-thankyou")) {
2570 strncpy(q->sound_thanks, var->value, sizeof(q->sound_thanks) - 1);
2571 } else if (!strcasecmp(var->name, "queue-reporthold")) {
2572 strncpy(q->sound_reporthold, var->value, sizeof(q->sound_reporthold) - 1);
2573 } else if (!strcasecmp(var->name, "announce-frequency")) {
2574 q->announcefrequency = atoi(var->value);
2575 } else if (!strcasecmp(var->name, "announce-round-seconds")) {
2576 q->roundingseconds = atoi(var->value);
2577 if(q->roundingseconds>60 || q->roundingseconds<0) {
2578 ast_log(LOG_WARNING, "'%s' isn't a valid value for queue-rounding-seconds using 0 instead at line %d of queue.conf\n", var->value, var->lineno);
2579 q->roundingseconds=0;
2581 } else if (!strcasecmp(var->name, "announce-holdtime")) {
2582 q->announceholdtime = (!strcasecmp(var->value,"once")) ? 1 : ast_true(var->value);
2583 } else if (!strcasecmp(var->name, "retry")) {
2584 q->retry = atoi(var->value);
2585 } else if (!strcasecmp(var->name, "wrapuptime")) {
2586 q->wrapuptime = atoi(var->value);
2587 } else if (!strcasecmp(var->name, "maxlen")) {
2588 q->maxlen = atoi(var->value);
2589 } else if (!strcasecmp(var->name, "servicelevel")) {
2590 q->servicelevel= atoi(var->value);
2591 } else if (!strcasecmp(var->name, "strategy")) {
2592 q->strategy = strat2int(var->value);
2593 if (q->strategy < 0) {
2594 ast_log(LOG_WARNING, "'%s' isn't a valid strategy, using ringall instead\n", var->value);
2597 } else if (!strcasecmp(var->name, "joinempty")) {
2598 ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_JOINEMPTY);
2599 } else if (!strcasecmp(var->name, "leavewhenempty")) {
2600 ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_LEAVEWHENEMPTY);
2601 } else if (!strcasecmp(var->name, "eventwhencalled")) {
2602 ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_EVENTWHENCALLED);
2603 } else if (!strcasecmp(var->name, "reportholdtime")) {
2604 ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_REPORTHOLDTIME);
2605 } else if (!strcasecmp(var->name, "memberdelay")) {
2606 q->memberdelay = atoi(var->value);
2607 } else if (!strcasecmp(var->name, "weight")) {
2608 q->weight = atoi(var->value);
2611 } else if (!strcasecmp(var->name, "timeoutrestart")) {
2612 ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_TIMEOUTRESTART);
2614 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queue.conf\n", cat, var->name, var->lineno);
2619 q->retry = DEFAULT_RETRY;
2621 q->timeout = DEFAULT_TIMEOUT;
2625 ast_mutex_unlock(&q->lock);
2632 /* Initialize global settings */
2633 queue_persistent_members = 0;
2634 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
2635 queue_persistent_members = ast_true(general_val);
2637 cat = ast_category_browse(cfg, cat);
2639 ast_config_destroy(cfg);
2644 if (ast_test_flag(q, QUEUE_FLAG_DEAD)) {
2652 ast_log(LOG_WARNING, "XXX Leaking a little memory :( XXX\n");
2654 for (cur = q->members; cur; cur = cur->next)
2655 cur->status = ast_device_state(cur->interface);
2660 ast_mutex_unlock(&qlock);
2663 static char *status2str(int status, char *buf, int buflen)
2666 case AST_DEVICE_UNKNOWN:
2667 strncpy(buf, "unknown", buflen - 1);
2669 case AST_DEVICE_NOT_INUSE:
2670 strncpy(buf, "notinuse", buflen - 1);
2672 case AST_DEVICE_INUSE:
2673 strncpy(buf, "inuse", buflen - 1);
2675 case AST_DEVICE_BUSY:
2676 strncpy(buf, "busy", buflen - 1);
2678 case AST_DEVICE_INVALID:
2679 strncpy(buf, "invalid", buflen - 1);
2681 case AST_DEVICE_UNAVAILABLE:
2682 strncpy(buf, "unavailable", buflen - 1);
2685 snprintf(buf, buflen, "unknown status %d", status);
2690 static int __queues_show(int fd, int argc, char **argv, int queue_show)
2692 struct ast_call_queue *q;
2693 struct queue_ent *qe;
2698 char calls[80] = "";
2699 char tmpbuf[80] = "";
2703 if ((!queue_show && argc != 2) || (queue_show && argc != 3))
2704 return RESULT_SHOWUSAGE;
2705 ast_mutex_lock(&qlock);
2708 ast_mutex_unlock(&qlock);
2710 ast_cli(fd, "No such queue: %s.\n",argv[2]);
2712 ast_cli(fd, "No queues.\n");
2713 return RESULT_SUCCESS;
2716 ast_mutex_lock(&q->lock);
2718 if (strcasecmp(q->name, argv[2]) != 0) {
2719 ast_mutex_unlock(&q->lock);
2722 ast_cli(fd, "No such queue: %s.\n",argv[2]);
2729 snprintf(max, sizeof(max), "%d", q->maxlen);
2731 strncpy(max, "unlimited", sizeof(max) - 1);
2733 if(q->callscompleted > 0)
2734 sl = 100*((float)q->callscompletedinsl/(float)q->callscompleted);
2735 ast_cli(fd, "%-12.12s has %d calls (max %s) in '%s' strategy (%ds holdtime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds\n",
2736 q->name, q->count, max, int2strat(q->strategy), q->holdtime, q->weight, q->callscompleted, q->callsabandoned,sl,q->servicelevel);
2738 ast_cli(fd, " Members: \n");
2739 for (mem = q->members; mem; mem = mem->next) {
2741 snprintf(max, sizeof(max) - 20, " with penalty %d", mem->penalty);
2745 strncat(max, " (dynamic)", sizeof(max) - strlen(max) - 1);
2747 strncat(max, " (paused)", sizeof(max) - strlen(max) - 1);
2749 snprintf(max + strlen(max), sizeof(max) - strlen(max), " (%s)", status2str(mem->status, tmpbuf, sizeof(tmpbuf)));
2751 snprintf(calls, sizeof(calls), " has taken %d calls (last was %ld secs ago)",
2752 mem->calls, (long)(time(NULL) - mem->lastcall));
2754 strncpy(calls, " has taken no calls yet", sizeof(calls) - 1);