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? */
200 /* We define a custom "local user" structure because we
201 use it not only for keeping track of what is in use but
202 also for keeping track of who we're dialing. */
205 struct ast_channel *chan;
210 unsigned int flags; /* flag bits */
212 struct member *member;
213 struct localuser *next;
219 struct ast_call_queue *parent; /* What queue is our parent */
220 char moh[80]; /* Name of musiconhold to be used */
221 char announce[80]; /* Announcement to play for member when call is answered */
222 char context[80]; /* Context when user exits queue */
223 int pos; /* Where we are in the queue */
224 int prio; /* Our priority */
225 int last_pos_said; /* Last position we told the user */
226 time_t last_pos; /* Last time we told the user their position */
227 int opos; /* Where we started in the queue */
228 int handled; /* Whether our call was handled */
229 time_t start; /* When we started holding */
230 time_t expire; /* When this entry should expire (time out of queue) */
231 struct ast_channel *chan; /* Our channel */
232 struct queue_ent *next; /* The next queue entry */
236 char interface[80]; /* Technology/Location */
237 int penalty; /* Are we a last resort? */
238 int calls; /* Number of calls serviced by this member */
239 int dynamic; /* Are we dynamically added? */
240 int status; /* Status of queue member */
241 int paused; /* Are we paused (not accepting calls)? */
242 time_t lastcall; /* When last successful call was hungup */
243 struct member *next; /* Next member */
246 struct ast_call_queue {
248 char name[80]; /* Name of the queue */
249 char moh[80]; /* Name of musiconhold to be used */
250 char announce[80]; /* Announcement to play when call is answered */
251 char context[80]; /* Context for this queue */
252 unsigned int flags; /* flag bits */
253 int strategy; /* Queueing strategy */
254 int announcefrequency; /* How often to announce their position */
255 int roundingseconds; /* How many seconds do we round to? */
256 int announceholdtime; /* When to announce holdtime: 0 = never, -1 = every announcement, 1 = only once */
257 int holdtime; /* Current avg holdtime for this queue, based on recursive boxcar filter */
258 int callscompleted; /* Number of queue calls completed */
259 int callsabandoned; /* Number of queue calls abandoned */
260 int servicelevel; /* seconds setting for servicelevel*/
261 int callscompletedinsl; /* Number of queue calls answered with servicelevel*/
262 char monfmt[8]; /* Format to use when recording calls */
263 char sound_next[80]; /* Sound file: "Your call is now first in line" (def. queue-youarenext) */
264 char sound_thereare[80]; /* Sound file: "There are currently" (def. queue-thereare) */
265 char sound_calls[80]; /* Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting)*/
266 char sound_holdtime[80]; /* Sound file: "The current estimated total holdtime is" (def. queue-holdtime) */
267 char sound_minutes[80]; /* Sound file: "minutes." (def. queue-minutes) */
268 char sound_lessthan[80]; /* Sound file: "less-than" (def. queue-lessthan) */
269 char sound_seconds[80]; /* Sound file: "seconds." (def. queue-seconds) */
270 char sound_thanks[80]; /* Sound file: "Thank you for your patience." (def. queue-thankyou) */
271 char sound_reporthold[80]; /* Sound file: "Hold time" (def. queue-reporthold) */
273 int count; /* How many entries are in the queue */
274 int maxlen; /* Max number of entries in queue */
275 int wrapuptime; /* Wrapup Time */
277 int retry; /* Retry calling everyone after this amount of time */
278 int timeout; /* How long to wait for an answer */
279 int weight; /* This queue's respective weight */
281 /* Queue strategy things */
282 int rrpos; /* Round Robin - position */
283 int memberdelay; /* Seconds to delay connecting member to caller */
285 struct member *members; /* Member channels to be tried */
286 struct queue_ent *head; /* Start of the actual queue */
287 struct ast_call_queue *next; /* Next call queue */
290 static struct ast_call_queue *queues = NULL;
291 AST_MUTEX_DEFINE_STATIC(qlock);
294 static char *int2strat(int strategy)
297 for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
298 if (strategy == strategies[x].strategy)
299 return strategies[x].name;
304 static int strat2int(char *strategy)
307 for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
308 if (!strcasecmp(strategy, strategies[x].name))
309 return strategies[x].strategy;
314 /* Insert the 'new' entry after the 'prev' entry of queue 'q' */
315 static inline void insert_entry(struct ast_call_queue *q,
316 struct queue_ent *prev, struct queue_ent *new, int *pos)
318 struct queue_ent *cur;
335 static int has_no_members(struct ast_call_queue *q)
337 struct member *member;
340 while(empty && member) {
341 switch(member->status) {
342 case AST_DEVICE_UNAVAILABLE:
343 case AST_DEVICE_INVALID:
344 /* Not logged on, etc */
350 member = member->next;
360 static void *changethread(void *data)
362 struct ast_call_queue *q;
363 struct statechange *sc = data;
368 technology = ast_strdupa(sc->dev);
369 loc = strchr(technology, '/');
374 ast_log(LOG_WARNING, "Can't change device '%s' with no technology!\n", sc->dev);
379 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d'\n", technology, loc, sc->state);
380 ast_mutex_lock(&qlock);
381 for (q = queues; q; q = q->next) {
382 ast_mutex_lock(&q->lock);
385 if (!strcasecmp(sc->dev, cur->interface)) {
386 if (cur->status != sc->state) {
387 cur->status = sc->state;
388 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
397 q->name, cur->interface, cur->dynamic ? "dynamic" : "static",
398 cur->penalty, cur->calls, cur->lastcall, cur->status, cur->paused);
403 ast_mutex_unlock(&q->lock);
405 ast_mutex_unlock(&qlock);
407 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d'\n", technology, loc, sc->state);
412 static int statechange_queue(const char *dev, int state, void *ign)
414 /* Avoid potential for deadlocks by spawning a new thread to handle
416 struct statechange *sc;
420 sc = malloc(sizeof(struct statechange) + strlen(dev) + 1);
423 strcpy(sc->dev, dev);
424 pthread_attr_init(&attr);
425 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
426 if (ast_pthread_create(&t, &attr, changethread, sc)) {
427 ast_log(LOG_WARNING, "Failed to create update thread!\n");
434 static int join_queue(char *queuename, struct queue_ent *qe)
436 struct ast_call_queue *q;
437 struct queue_ent *cur, *prev = NULL;
442 ast_mutex_lock(&qlock);
443 for (q = queues; q; q = q->next) {
444 if (!strcasecmp(q->name, queuename)) {
445 /* This is our one */
446 ast_mutex_lock(&q->lock);
447 if ((!has_no_members(q) || ast_test_flag(q, QUEUE_FLAG_JOINEMPTY)) && (!q->maxlen || (q->count < q->maxlen))) {
448 /* There's space for us, put us at the right position inside
450 * Take into account the priority of the calling user */
455 /* We have higher priority than the current user, enter
456 * before him, after all the other users with priority
457 * higher or equal to our priority. */
458 if ((!inserted) && (qe->prio > cur->prio)) {
459 insert_entry(q, prev, qe, &pos);
466 /* No luck, join at the end of the queue */
468 insert_entry(q, prev, qe, &pos);
469 strncpy(qe->moh, q->moh, sizeof(qe->moh) - 1);
470 strncpy(qe->announce, q->announce, sizeof(qe->announce) - 1);
471 strncpy(qe->context, q->context, sizeof(qe->context) - 1);
474 manager_event(EVENT_FLAG_CALL, "Join",
475 "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\n",
477 qe->chan->cid.cid_num ? qe->chan->cid.cid_num : "unknown",
478 qe->chan->cid.cid_name ? qe->chan->cid.cid_name : "unknown",
479 q->name, qe->pos, q->count );
481 ast_log(LOG_NOTICE, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
484 ast_mutex_unlock(&q->lock);
488 ast_mutex_unlock(&qlock);
492 static void free_members(struct ast_call_queue *q, int all)
494 /* Free non-dynamic members */
495 struct member *curm, *next, *prev;
500 if (all || !curm->dynamic) {
512 static void destroy_queue(struct ast_call_queue *q)
514 struct ast_call_queue *cur, *prev = NULL;
515 ast_mutex_lock(&qlock);
516 for (cur = queues; cur; cur = cur->next) {
519 prev->next = cur->next;
526 ast_mutex_unlock(&qlock);
528 ast_mutex_destroy(&q->lock);
532 static int play_file(struct ast_channel *chan, char *filename)
536 ast_stopstream(chan);
537 res = ast_streamfile(chan, filename, chan->language);
540 res = ast_waitstream(chan, "");
545 ast_log(LOG_WARNING, "ast_streamfile failed on %s \n", chan->name);
548 ast_stopstream(chan);
553 static int say_position(struct queue_ent *qe)
555 int res = 0, avgholdmins, avgholdsecs;
558 /* Check to see if this is ludicrous -- if we just announced position, don't do it again*/
560 if ( (now - qe->last_pos) < 15 )
563 /* If either our position has changed, or we are over the freq timer, say position */
564 if ( (qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency) )
567 ast_moh_stop(qe->chan);
568 /* Say we're next, if we are */
570 res += play_file(qe->chan, qe->parent->sound_next);
573 res += play_file(qe->chan, qe->parent->sound_thereare);
574 res += ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */
575 res += play_file(qe->chan, qe->parent->sound_calls);
577 /* Round hold time to nearest minute */
578 avgholdmins = abs(( (qe->parent->holdtime + 30) - (now - qe->start) ) / 60);
580 /* If they have specified a rounding then round the seconds as well */
581 if(qe->parent->roundingseconds) {
582 avgholdsecs = (abs(( (qe->parent->holdtime + 30) - (now - qe->start) )) - 60 * avgholdmins) / qe->parent->roundingseconds;
583 avgholdsecs*= qe->parent->roundingseconds;
588 if (option_verbose > 2)
589 ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
591 /* If the hold time is >1 min, if it's enabled, and if it's not
592 supposed to be only once and we have already said it, say it */
593 if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) && (!(qe->parent->announceholdtime==1 && qe->last_pos)) ) {
594 res += play_file(qe->chan, qe->parent->sound_holdtime);
596 if (avgholdmins < 2) {
597 res += play_file(qe->chan, qe->parent->sound_lessthan);
598 res += ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, (char *)NULL);
600 res += ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, (char*) NULL);
601 res += play_file(qe->chan, qe->parent->sound_minutes);
604 res += ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, (char*) NULL);
605 res += play_file(qe->chan, qe->parent->sound_seconds);
611 /* Set our last_pos indicators */
613 qe->last_pos_said = qe->pos;
615 if (option_verbose > 2)
616 ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n", qe->chan->name, qe->parent->name, qe->pos);
617 res += play_file(qe->chan, qe->parent->sound_thanks);
618 ast_moh_start(qe->chan, qe->moh);
623 static void record_abandoned(struct queue_ent *qe)
625 ast_mutex_lock(&qe->parent->lock);
626 qe->parent->callsabandoned++;
627 ast_mutex_unlock(&qe->parent->lock);
630 static void recalc_holdtime(struct queue_ent *qe)
632 int oldvalue, newvalue;
634 /* Calculate holdtime using a recursive boxcar filter */
635 /* Thanks to SRT for this contribution */
636 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
638 newvalue = time(NULL) - qe->start;
640 ast_mutex_lock(&qe->parent->lock);
641 if (newvalue <= qe->parent->servicelevel)
642 qe->parent->callscompletedinsl++;
643 oldvalue = qe->parent->holdtime;
644 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newvalue) >> 2;
645 ast_mutex_unlock(&qe->parent->lock);
649 static void leave_queue(struct queue_ent *qe)
651 struct ast_call_queue *q;
652 struct queue_ent *cur, *prev = NULL;
657 ast_mutex_lock(&q->lock);
665 /* Take us out of the queue */
666 manager_event(EVENT_FLAG_CALL, "Leave",
667 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\n",
668 qe->chan->name, q->name, q->count);
670 ast_log(LOG_NOTICE, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
672 /* Take us out of the queue */
674 prev->next = cur->next;
678 /* Renumber the people after us in the queue based on a new count */
684 ast_mutex_unlock(&q->lock);
685 if (ast_test_flag(q, QUEUE_FLAG_DEAD) && !q->count) {
686 /* It's dead and nobody is in it, so kill it */
691 static void hanguptree(struct localuser *outgoing, struct ast_channel *exception)
693 /* Hang up a tree of stuff */
694 struct localuser *oo;
696 /* Hangup any existing lines we have open */
697 if (outgoing->chan && (outgoing->chan != exception))
698 ast_hangup(outgoing->chan);
700 outgoing=outgoing->next;
705 static int update_status(struct ast_call_queue *q, struct member *member, int status)
708 /* Since a reload could have taken place, we have to traverse the list to
709 be sure it's still valid */
710 ast_mutex_lock(&q->lock);
714 cur->status = status;
715 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
724 q->name, cur->interface, cur->dynamic ? "dynamic" : "static",
725 cur->penalty, cur->calls, cur->lastcall, cur->status, cur->paused);
731 ast_mutex_unlock(&q->lock);
735 static int update_dial_status(struct ast_call_queue *q, struct member *member, int status)
737 if (status == AST_CAUSE_BUSY)
738 status = AST_DEVICE_BUSY;
739 else if (status == AST_CAUSE_UNREGISTERED)
740 status = AST_DEVICE_UNAVAILABLE;
741 else if (status == AST_CAUSE_NOSUCHDRIVER)
742 status = AST_DEVICE_INVALID;
744 status = AST_DEVICE_UNKNOWN;
745 return update_status(q, member, status);
748 static int compare_weight(struct ast_call_queue *req_q, struct localuser *req_user, char *qname)
750 /* traverse all defined queues which have calls waiting and contain this member
751 return 0 if no other queue has precedence (higher weight) or 1 if found */
752 struct ast_call_queue *q;
754 int found = 0, weight = 0, calls = 0;
757 strncpy(name, req_q->name, sizeof(name) - 1);
758 weight = req_q->weight;
759 calls = req_q->count;
761 ast_mutex_lock(&qlock);
762 for (q = queues; q; q = q->next) { /* spin queues */
763 ast_mutex_lock(&q->lock);
764 if (!strcasecmp(q->name, name)) { /* don't check myself */
765 ast_mutex_unlock(&q->lock);
768 if (q->count && q->members) { /* check only if calls waiting and has members */
769 for (mem = q->members; mem; mem = mem->next) { /* spin members */
770 if (!strcasecmp(mem->interface, req_user->interface)) {
771 ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
772 if (q->weight > weight) {
773 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);
775 strncpy(qname, q->name, sizeof(qname) - 1);
776 break; /* stop looking for more members */
781 ast_mutex_unlock(&q->lock);
785 ast_mutex_unlock(&qlock);
791 static int ring_entry(struct queue_ent *qe, struct localuser *tmp, int *busies)
799 if (use_weight) { /* fast path */
800 if (compare_weight(qe->parent,tmp,qname)) {
801 ast_verbose(VERBOSE_PREFIX_3 "Attempt (%s: %s) delayed by higher priority queue (%s).\n", qe->parent->name, tmp->interface, qname);
803 ast_cdr_busy(qe->chan->cdr);
809 if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
811 ast_log(LOG_DEBUG, "Wrapuptime not yet expired for %s\n", tmp->interface);
813 ast_cdr_busy(qe->chan->cdr);
819 if (tmp->member->paused) {
821 ast_log(LOG_DEBUG, "%s paused, can't receive call\n", tmp->interface);
823 ast_cdr_busy(qe->chan->cdr);
828 strncpy(tech, tmp->interface, sizeof(tech) - 1);
829 if ((location = strchr(tech, '/')))
834 /* Request the peer */
835 tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
836 if (!tmp->chan) { /* If we can't, just go on to the next call */
838 ast_log(LOG_NOTICE, "Unable to create channel of type '%s' for Queue\n", cur->tech);
841 ast_cdr_busy(qe->chan->cdr);
843 update_dial_status(qe->parent, tmp->member, status);
846 } else if (status != tmp->oldstatus)
847 update_dial_status(qe->parent, tmp->member, status);
849 tmp->chan->appl = "AppQueue";
850 tmp->chan->data = "(Outgoing Line)";
851 tmp->chan->whentohangup = 0;
852 if (tmp->chan->cid.cid_num)
853 free(tmp->chan->cid.cid_num);
854 tmp->chan->cid.cid_num = NULL;
855 if (tmp->chan->cid.cid_name)
856 free(tmp->chan->cid.cid_name);
857 tmp->chan->cid.cid_name = NULL;
858 if (tmp->chan->cid.cid_ani)
859 free(tmp->chan->cid.cid_ani);
860 tmp->chan->cid.cid_ani = NULL;
861 if (qe->chan->cid.cid_num)
862 tmp->chan->cid.cid_num = strdup(qe->chan->cid.cid_num);
863 if (qe->chan->cid.cid_name)
864 tmp->chan->cid.cid_name = strdup(qe->chan->cid.cid_name);
865 if (qe->chan->cid.cid_ani)
866 tmp->chan->cid.cid_ani = strdup(qe->chan->cid.cid_ani);
868 /* Inherit specially named variables from parent channel */
869 ast_channel_inherit_variables(qe->chan, tmp->chan);
871 /* Presense of ADSI CPE on outgoing channel follows ours */
872 tmp->chan->adsicpe = qe->chan->adsicpe;
874 /* Place the call, but don't wait on the answer */
875 res = ast_call(tmp->chan, location, 0);
877 /* Again, keep going even if there's an error */
879 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
880 else if (option_verbose > 2)
881 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface);
882 ast_hangup(tmp->chan);
888 if (ast_test_flag(qe->parent, QUEUE_FLAG_EVENTWHENCALLED)) {
889 manager_event(EVENT_FLAG_AGENT, "AgentCalled",
890 "AgentCalled: %s\r\n"
891 "ChannelCalling: %s\r\n"
893 "CallerIDName: %s\r\n"
897 tmp->interface, qe->chan->name,
898 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
899 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
900 qe->chan->context, qe->chan->exten, qe->chan->priority);
902 if (option_verbose > 2)
903 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface);
908 static int ring_one(struct queue_ent *qe, struct localuser *outgoing, int *busies)
910 struct localuser *cur;
911 struct localuser *best;
917 if (cur->stillgoing && /* Not already done */
918 !cur->chan && /* Isn't already going */
919 (!best || (cur->metric < bestmetric))) { /* We haven't found one yet, or it's better */
920 bestmetric = cur->metric;
926 if (!qe->parent->strategy) {
927 /* Ring everyone who shares this best metric (for ringall) */
930 if (cur->stillgoing && !cur->chan && (cur->metric <= bestmetric)) {
932 ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
933 ring_entry(qe, cur, busies);
938 /* Ring just the best channel */
940 ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric);
941 ring_entry(qe, best, busies);
944 } while (best && !best->chan);
947 ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n");
953 static int store_next(struct queue_ent *qe, struct localuser *outgoing)
955 struct localuser *cur;
956 struct localuser *best;
961 if (cur->stillgoing && /* Not already done */
962 !cur->chan && /* Isn't already going */
963 (!best || (cur->metric < bestmetric))) { /* We haven't found one yet, or it's better */
964 bestmetric = cur->metric;
970 /* Ring just the best channel */
972 ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric);
973 qe->parent->rrpos = best->metric % 1000;
975 /* Just increment rrpos */
976 if (!ast_test_flag(qe->parent, QUEUE_FLAG_WRAPPED)) {
977 /* No more channels, start over */
978 qe->parent->rrpos = 0;
980 /* Prioritize next entry */
984 ast_clear_flag(qe->parent, QUEUE_FLAG_WRAPPED);
988 static int valid_exit(struct queue_ent *qe, char digit)
991 if (ast_strlen_zero(qe->context))
995 if (ast_exists_extension(qe->chan, qe->context, tmp, 1, qe->chan->cid.cid_num)) {
996 strncpy(qe->chan->context, qe->context, sizeof(qe->chan->context) - 1);
997 strncpy(qe->chan->exten, tmp, sizeof(qe->chan->exten) - 1);
998 qe->chan->priority = 0;
1004 #define AST_MAX_WATCHERS 256
1006 #define BUILD_STATS do { \
1013 /* Keep track of important channels */ \
1014 if (o->stillgoing) { \
1017 watchers[pos++] = o->chan; \
1026 static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser *outgoing, int *to, struct ast_flags *flags, char *digit, int prebusies)
1028 char *queue = qe->parent->name;
1029 struct localuser *o;
1033 int sentringing = 0;
1034 int numbusies = prebusies;
1038 struct ast_frame *f;
1039 struct localuser *peer = NULL;
1040 struct ast_channel *watchers[AST_MAX_WATCHERS];
1042 struct ast_channel *winner;
1043 struct ast_channel *in = qe->chan;
1045 while(*to && !peer) {
1047 if ((found < 0) && stillgoing && !qe->parent->strategy) {
1048 /* On "ringall" strategy we only move to the next penalty level
1049 when *all* ringing phones are done in the current penalty level */
1050 ring_one(qe, outgoing, &numbusies);
1054 if (numlines == (numbusies + numnochan)) {
1055 ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
1057 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan);
1062 winner = ast_waitfor_n(watchers, pos, to);
1065 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
1067 if (option_verbose > 2)
1068 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
1070 ast_copy_flags(flags, o, QUEUE_FLAG_REDIR_IN | QUEUE_FLAG_REDIR_OUT | QUEUE_FLAG_DISCON_IN | QUEUE_FLAG_DISCON_OUT);
1072 } else if (o->chan && (o->chan == winner)) {
1073 if (!ast_strlen_zero(o->chan->call_forward)) {
1074 char tmpchan[256]="";
1077 strncpy(tmpchan, o->chan->call_forward, sizeof(tmpchan) - 1);
1078 if ((stuff = strchr(tmpchan, '/'))) {
1083 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
1087 /* Before processing channel, go ahead and check for forwarding */
1088 if (option_verbose > 2)
1089 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
1090 /* Setup parameters */
1091 o->chan = ast_request(tech, in->nativeformats, stuff, &status);
1092 if (status != o->oldstatus)
1093 update_dial_status(qe->parent, o->member, status);
1095 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
1099 if (o->chan->cid.cid_num)
1100 free(o->chan->cid.cid_num);
1101 o->chan->cid.cid_num = NULL;
1102 if (o->chan->cid.cid_name)
1103 free(o->chan->cid.cid_name);
1104 o->chan->cid.cid_name = NULL;
1106 if (in->cid.cid_num) {
1107 o->chan->cid.cid_num = strdup(in->cid.cid_num);
1108 if (!o->chan->cid.cid_num)
1109 ast_log(LOG_WARNING, "Out of memory\n");
1111 if (in->cid.cid_name) {
1112 o->chan->cid.cid_name = strdup(in->cid.cid_name);
1113 if (!o->chan->cid.cid_name)
1114 ast_log(LOG_WARNING, "Out of memory\n");
1116 strncpy(o->chan->accountcode, in->accountcode, sizeof(o->chan->accountcode) - 1);
1117 o->chan->cdrflags = in->cdrflags;
1119 if (in->cid.cid_ani) {
1120 if (o->chan->cid.cid_ani)
1121 free(o->chan->cid.cid_ani);
1122 o->chan->cid.cid_ani = malloc(strlen(in->cid.cid_ani) + 1);
1123 if (o->chan->cid.cid_ani)
1124 strncpy(o->chan->cid.cid_ani, in->cid.cid_ani, strlen(in->cid.cid_ani) + 1);
1126 ast_log(LOG_WARNING, "Out of memory\n");
1128 if (o->chan->cid.cid_rdnis)
1129 free(o->chan->cid.cid_rdnis);
1130 if (!ast_strlen_zero(in->macroexten))
1131 o->chan->cid.cid_rdnis = strdup(in->macroexten);
1133 o->chan->cid.cid_rdnis = strdup(in->exten);
1134 if (ast_call(o->chan, tmpchan, 0)) {
1135 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
1137 ast_hangup(o->chan);
1142 /* Hangup the original channel now, in case we needed it */
1146 f = ast_read(winner);
1148 if (f->frametype == AST_FRAME_CONTROL) {
1149 switch(f->subclass) {
1150 case AST_CONTROL_ANSWER:
1151 /* This is our guy if someone answered. */
1153 ast_copy_flags(flags, o, QUEUE_FLAG_REDIR_IN | QUEUE_FLAG_REDIR_OUT | QUEUE_FLAG_DISCON_IN | QUEUE_FLAG_DISCON_OUT);
1154 if (option_verbose > 2)
1155 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
1157 ast_copy_flags(flags, o, QUEUE_FLAG_REDIR_IN & QUEUE_FLAG_REDIR_OUT & QUEUE_FLAG_DISCON_IN & QUEUE_FLAG_DISCON_OUT);
1160 case AST_CONTROL_BUSY:
1161 if (option_verbose > 2)
1162 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
1165 ast_cdr_busy(in->cdr);
1166 ast_hangup(o->chan);
1168 if (qe->parent->strategy)
1169 ring_one(qe, outgoing, &numbusies);
1172 case AST_CONTROL_CONGESTION:
1173 if (option_verbose > 2)
1174 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
1177 ast_cdr_busy(in->cdr);
1178 ast_hangup(o->chan);
1180 if (qe->parent->strategy)
1181 ring_one(qe, outgoing, &numbusies);
1184 case AST_CONTROL_RINGING:
1185 if (option_verbose > 2)
1186 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
1189 ast_indicate(in, AST_CONTROL_RINGING);
1194 case AST_CONTROL_OFFHOOK:
1195 /* Ignore going off hook */
1198 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
1204 ast_hangup(o->chan);
1206 if (qe->parent->strategy)
1207 ring_one(qe, outgoing, &numbusies);
1215 if (f && (f->frametype != AST_FRAME_VOICE))
1216 printf("Frame type: %d, %d\n", f->frametype, f->subclass);
1217 else if (!f || (f->frametype != AST_FRAME_VOICE))
1218 printf("Hangup received on %s\n", in->name);
1220 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
1225 if (f && (f->frametype == AST_FRAME_DTMF) && ast_test_flag(flags, QUEUE_FLAG_DISCON_OUT) && (f->subclass == '*')) {
1226 if (option_verbose > 3)
1227 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
1231 if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass != '*') && valid_exit(qe, f->subclass)) {
1232 if (option_verbose > 3)
1233 ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c", f->subclass);
1239 if (!*to && (option_verbose > 2))
1240 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
1247 static int is_our_turn(struct queue_ent *qe)
1249 struct queue_ent *ch;
1252 /* Atomically read the parent head -- does not need a lock */
1253 ch = qe->parent->head;
1254 /* If we are now at the top of the head, break out */
1257 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
1261 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
1267 static int wait_our_turn(struct queue_ent *qe, int ringing)
1271 /* This is the holding pen for callers 2 through maxlen */
1273 if (is_our_turn(qe))
1276 /* If we have timed out, break out */
1277 if (qe->expire && (time(NULL) > qe->expire))
1280 /* leave the queue if no agents, if enabled */
1281 if (ast_test_flag(qe->parent, QUEUE_FLAG_LEAVEWHENEMPTY) && has_no_members(qe->parent)) {
1286 /* Make a position announcement, if enabled */
1287 if (qe->parent->announcefrequency && !ringing)
1290 /* Wait a second before checking again */
1291 res = ast_waitfordigit(qe->chan, RECHECK * 1000);
1298 static int update_queue(struct ast_call_queue *q, struct member *member)
1301 /* Since a reload could have taken place, we have to traverse the list to
1302 be sure it's still valid */
1303 ast_mutex_lock(&q->lock);
1306 if (member == cur) {
1307 time(&cur->lastcall);
1313 q->callscompleted++;
1314 ast_mutex_unlock(&q->lock);
1318 static int calc_metric(struct ast_call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct localuser *tmp)
1320 switch (q->strategy) {
1321 case QUEUE_STRATEGY_RINGALL:
1322 /* Everyone equal, except for penalty */
1323 tmp->metric = mem->penalty * 1000000;
1325 case QUEUE_STRATEGY_ROUNDROBIN:
1327 if (!ast_test_flag(q, QUEUE_FLAG_WRAPPED)) {
1328 /* No more channels, start over */
1331 /* Prioritize next entry */
1334 ast_clear_flag(q, QUEUE_FLAG_WRAPPED);
1337 case QUEUE_STRATEGY_RRMEMORY:
1338 if (pos < q->rrpos) {
1339 tmp->metric = 1000 + pos;
1341 if (pos > q->rrpos) {
1342 /* Indicate there is another priority */
1343 ast_set_flag(q, QUEUE_FLAG_WRAPPED);
1347 tmp->metric += mem->penalty * 1000000;
1349 case QUEUE_STRATEGY_RANDOM:
1350 tmp->metric = rand() % 1000;
1351 tmp->metric += mem->penalty * 1000000;
1353 case QUEUE_STRATEGY_FEWESTCALLS:
1354 tmp->metric = mem->calls;
1355 tmp->metric += mem->penalty * 1000000;
1357 case QUEUE_STRATEGY_LEASTRECENT:
1361 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
1362 tmp->metric += mem->penalty * 1000000;
1365 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
1371 static int try_calling(struct queue_ent *qe, char *ooptions, char *announceoverride, char *url, int *go_on)
1374 struct localuser *outgoing=NULL, *tmp = NULL;
1376 struct ast_flags flags;
1377 char restofit[AST_MAX_EXTENSION];
1378 char oldexten[AST_MAX_EXTENSION]="";
1379 char oldcontext[AST_MAX_EXTENSION]="";
1380 char queuename[256]="";
1383 char *monitorfilename;
1384 struct ast_channel *peer;
1385 struct ast_channel *which;
1386 struct localuser *lpeer;
1387 struct member *member;
1388 int res = 0, bridge = 0;
1392 char *announce = NULL;
1396 struct ast_bridge_config config;
1397 /* Hold the lock while we setup the outgoing calls */
1398 ast_mutex_lock(&qe->parent->lock);
1400 ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n",
1402 strncpy(queuename, qe->parent->name, sizeof(queuename) - 1);
1404 cur = qe->parent->members;
1405 if (!ast_strlen_zero(qe->announce))
1406 announce = qe->announce;
1407 if (announceoverride && !ast_strlen_zero(announceoverride))
1408 announce = announceoverride;
1410 /* Get a technology/[device:]number pair */
1411 tmp = malloc(sizeof(struct localuser));
1413 ast_mutex_unlock(&qe->parent->lock);
1414 ast_log(LOG_WARNING, "Out of memory\n");
1417 memset(tmp, 0, sizeof(struct localuser));
1418 tmp->stillgoing = -1;
1420 for (; options && *options; options++)
1423 ast_set_flag(tmp, QUEUE_FLAG_REDIR_IN);
1426 ast_set_flag(tmp, QUEUE_FLAG_REDIR_OUT);
1429 ast_set_flag(tmp, QUEUE_FLAG_RINGBACKONLY);
1432 ast_set_flag(tmp, QUEUE_FLAG_MUSICONHOLD);
1435 ast_set_flag(tmp, QUEUE_FLAG_DATAQUALITY);
1438 ast_set_flag(tmp, QUEUE_FLAG_DISCON_IN);
1441 ast_set_flag(tmp, QUEUE_FLAG_DISCON_OUT);
1444 if ((now - qe->start >= qe->parent->timeout))
1450 ast_log(LOG_DEBUG, "Queue with URL=%s_\n", url);
1452 ast_log(LOG_DEBUG, "Simple queue (no URL)\n");
1455 tmp->member = cur; /* Never directly dereference! Could change on reload */
1456 tmp->oldstatus = cur->status;
1457 tmp->lastcall = cur->lastcall;
1458 strncpy(tmp->interface, cur->interface, sizeof(tmp->interface)-1);
1459 /* If we're dialing by extension, look at the extension to know what to dial */
1460 if ((newnum = strstr(tmp->interface, "/BYEXTENSION"))) {
1462 strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit) - 1);
1463 snprintf(newnum, sizeof(tmp->interface) - (newnum - tmp->interface), "%s%s", qe->chan->exten, restofit);
1465 ast_log(LOG_DEBUG, "Dialing by extension %s\n", tmp->interface);
1467 /* Special case: If we ring everyone, go ahead and ring them, otherwise
1468 just calculate their metric for the appropriate strategy */
1469 calc_metric(qe->parent, cur, x++, qe, tmp);
1470 /* Put them in the list of outgoing thingies... We're ready now.
1471 XXX If we're forcibly removed, these outgoing calls won't get
1473 tmp->next = outgoing;
1475 /* If this line is up, don't try anybody else */
1476 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
1481 if (qe->parent->timeout)
1482 to = qe->parent->timeout * 1000;
1485 ring_one(qe, outgoing, &numbusies);
1486 ast_mutex_unlock(&qe->parent->lock);
1487 lpeer = wait_for_answer(qe, outgoing, &to, &flags, &digit, numbusies);
1488 ast_mutex_lock(&qe->parent->lock);
1489 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
1490 store_next(qe, outgoing);
1492 ast_mutex_unlock(&qe->parent->lock);
1499 /* Musta gotten hung up */
1500 record_abandoned(qe);
1503 if (digit && valid_exit(qe, digit))
1506 /* Nobody answered, next please? */
1510 ast_log(LOG_DEBUG, "%s: Nobody answered.\n", qe->chan->name);
1514 /* Ah ha! Someone answered within the desired timeframe. Of course after this
1515 we will always return with -1 so that it is hung up properly after the
1518 if (!strcmp(qe->chan->type,"Zap")) {
1519 zapx = !ast_test_flag(tmp, QUEUE_FLAG_DATAQUALITY);
1520 ast_channel_setoption(qe->chan,AST_OPTION_TONE_VERIFY,&zapx,sizeof(char),0);
1522 if (!strcmp(peer->type,"Zap")) {
1523 zapx = !ast_test_flag(tmp, QUEUE_FLAG_DATAQUALITY);
1524 ast_channel_setoption(peer,AST_OPTION_TONE_VERIFY,&zapx,sizeof(char),0);
1526 /* Update parameters for the queue */
1527 recalc_holdtime(qe);
1528 member = lpeer->member;
1529 hanguptree(outgoing, peer);
1531 if (announce || ast_test_flag(qe->parent, QUEUE_FLAG_REPORTHOLDTIME) || qe->parent->memberdelay) {
1533 res2 = ast_autoservice_start(qe->chan);
1535 if (qe->parent->memberdelay) {
1536 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
1537 res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
1539 if (!res2 && announce) {
1540 if (play_file(peer, announce))
1541 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", announce);
1543 if (!res2 && ast_test_flag(qe->parent, QUEUE_FLAG_REPORTHOLDTIME)) {
1544 if (!play_file(peer, qe->parent->sound_reporthold)) {
1549 holdtime = abs((now - qe->start) / 60);
1551 play_file(peer, qe->parent->sound_lessthan);
1552 ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL);
1554 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
1555 play_file(peer, qe->parent->sound_minutes);
1559 res2 |= ast_autoservice_stop(qe->chan);
1560 if (peer->_softhangup) {
1561 /* Agent must have hung up */
1562 ast_log(LOG_WARNING, "Agent on %s hungup on the customer. They're going to be pissed.\n", peer->name);
1563 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "AGENTDUMP", "%s", "");
1564 if (ast_test_flag(qe->parent, QUEUE_FLAG_EVENTWHENCALLED)) {
1565 manager_event(EVENT_FLAG_AGENT, "AgentDump",
1570 queuename, qe->chan->uniqueid, peer->name, member->interface);
1575 /* Caller must have hung up just before being connected*/
1576 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
1577 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
1578 record_abandoned(qe);
1583 /* Stop music on hold */
1584 ast_moh_stop(qe->chan);
1585 /* If appropriate, log that we have a destination channel */
1587 ast_cdr_setdestchan(qe->chan->cdr, peer->name);
1588 /* Make sure channels are compatible */
1589 res = ast_channel_make_compatible(qe->chan, peer);
1591 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "SYSCOMPAT", "%s", "");
1592 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
1596 /* Begin Monitoring */
1597 if (qe->parent->monfmt && *qe->parent->monfmt) {
1598 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
1599 if(pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper( qe->chan, "MONITOR_EXEC_ARGS"))
1603 if(monitorfilename) {
1604 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 );
1606 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
1608 if(ast_test_flag(qe->parent, QUEUE_FLAG_MONJOIN)) {
1609 ast_monitor_setjoinfiles(which, 1);
1612 /* Drop out of the queue at this point, to prepare for next caller */
1614 if( url && !ast_strlen_zero(url) && ast_channel_supports_html(peer) ) {
1616 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
1617 ast_channel_sendurl( peer, url );
1619 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "CONNECT", "%ld", (long)time(NULL) - qe->start);
1620 if (ast_test_flag(qe->parent, QUEUE_FLAG_EVENTWHENCALLED)) {
1621 manager_event(EVENT_FLAG_AGENT, "AgentConnect",
1626 "Holdtime: %ld\r\n",
1627 queuename, qe->chan->uniqueid, peer->name, member->interface, (long)time(NULL) - qe->start);
1629 strncpy(oldcontext, qe->chan->context, sizeof(oldcontext) - 1);
1630 strncpy(oldexten, qe->chan->exten, sizeof(oldexten) - 1);
1633 memset(&config,0,sizeof(struct ast_bridge_config));
1635 if (ast_test_flag(&flags, QUEUE_FLAG_REDIR_IN))
1636 ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
1637 if (ast_test_flag(&flags, QUEUE_FLAG_REDIR_OUT))
1638 ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
1639 if (ast_test_flag(&flags, QUEUE_FLAG_DISCON_IN))
1640 ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
1641 if (ast_test_flag(&flags, QUEUE_FLAG_DISCON_OUT))
1642 ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
1643 bridge = ast_bridge_call(qe->chan,peer,&config);
1645 if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
1646 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "TRANSFER", "%s|%s", qe->chan->exten, qe->chan->context);
1647 } else if (qe->chan->_softhangup) {
1648 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETECALLER", "%ld|%ld", (long)(callstart - qe->start), (long)(time(NULL) - callstart));
1649 if (ast_test_flag(qe->parent, QUEUE_FLAG_EVENTWHENCALLED)) {
1650 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
1657 "Reason: caller\r\n",
1658 queuename, qe->chan->uniqueid, peer->name, member->interface, (long)(callstart - qe->start), (long)(time(NULL) - callstart));
1661 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETEAGENT", "%ld|%ld", (long)(callstart - qe->start), (long)(time(NULL) - callstart));
1662 if (ast_test_flag(qe->parent, QUEUE_FLAG_EVENTWHENCALLED)) {
1663 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
1669 "Reason: agent\r\n",
1670 queuename, qe->chan->uniqueid, peer->name, (long)(callstart - qe->start), (long)(time(NULL) - callstart));
1675 if(bridge != AST_PBX_NO_HANGUP_PEER)
1677 update_queue(qe->parent, member);
1679 res = 1; /* JDG: bridge successfull, leave app_queue */
1681 res = bridge; /* bridge error, stay in the queue */
1684 hanguptree(outgoing, NULL);
1688 static int wait_a_bit(struct queue_ent *qe)
1690 /* Don't need to hold the lock while we setup the outgoing calls */
1691 int retrywait = qe->parent->retry * 1000;
1692 return ast_waitfordigit(qe->chan, retrywait);
1695 /* [PHM 06/26/03] */
1697 static struct member * interface_exists(struct ast_call_queue *q, char *interface)
1702 for (mem = q->members; mem; mem = mem->next)
1703 if (!strcmp(interface, mem->interface))
1710 static struct member *create_queue_node(char *interface, int penalty, int paused)
1714 /* Add a new member */
1716 cur = malloc(sizeof(struct member));
1719 memset(cur, 0, sizeof(struct member));
1720 cur->penalty = penalty;
1721 cur->paused = paused;
1722 strncpy(cur->interface, interface, sizeof(cur->interface) - 1);
1723 if (!strchr(cur->interface, '/'))
1724 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
1725 cur->status = ast_device_state(interface);
1731 /* Dump all members in a specific queue to the databse
1733 * <pm_family>/<queuename> = <interface>;<penalty>;<paused>;...
1736 static void dump_queue_members(struct ast_call_queue *pm_queue)
1738 struct member *cur_member = NULL;
1739 char value[PM_MAX_LEN];
1743 memset(value, 0, sizeof(value));
1746 cur_member = pm_queue->members;
1747 while (cur_member) {
1748 if (cur_member->dynamic) {
1749 value_len = strlen(value);
1750 res = snprintf(value+value_len, sizeof(value)-value_len, "%s;%d;%d;", cur_member->interface, cur_member->penalty, cur_member->paused);
1751 if (res != strlen(value + value_len)) {
1752 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
1756 cur_member = cur_member->next;
1759 if (!ast_strlen_zero(value) && !cur_member) {
1760 if (ast_db_put(pm_family, pm_queue->name, value))
1761 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
1763 /* Delete the entry if the queue is empty or there is an error */
1764 ast_db_del(pm_family, pm_queue->name);
1771 static int remove_from_queue(char *queuename, char *interface)
1773 struct ast_call_queue *q;
1774 struct member *last_member, *look;
1775 int res = RES_NOSUCHQUEUE;
1777 ast_mutex_lock(&qlock);
1778 for (q = queues ; q ; q = q->next) {
1779 ast_mutex_lock(&q->lock);
1780 if (!strcmp(q->name, queuename)) {
1781 if ((last_member = interface_exists(q, interface))) {
1782 if ((look = q->members) == last_member) {
1783 q->members = last_member->next;
1785 while (look != NULL) {
1786 if (look->next == last_member) {
1787 look->next = last_member->next;
1794 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
1797 q->name, last_member->interface);
1800 if (queue_persistent_members)
1801 dump_queue_members(q);
1807 ast_mutex_unlock(&q->lock);
1810 ast_mutex_unlock(&q->lock);
1812 ast_mutex_unlock(&qlock);
1816 static int add_to_queue(char *queuename, char *interface, int penalty, int paused)
1818 struct ast_call_queue *q;
1819 struct member *new_member;
1820 int res = RES_NOSUCHQUEUE;
1822 ast_mutex_lock(&qlock);
1823 for (q = queues ; q ; q = q->next) {
1824 ast_mutex_lock(&q->lock);
1825 if (!strcmp(q->name, queuename)) {
1826 if (interface_exists(q, interface) == NULL) {
1827 new_member = create_queue_node(interface, penalty, paused);
1829 if (new_member != NULL) {
1830 new_member->dynamic = 1;
1831 new_member->next = q->members;
1832 q->members = new_member;
1833 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
1836 "Membership: %s\r\n"
1838 "CallsTaken: %d\r\n"
1842 q->name, new_member->interface, new_member->dynamic ? "dynamic" : "static",
1843 new_member->penalty, new_member->calls, new_member->lastcall, new_member->status, new_member->paused);
1845 if (queue_persistent_members)
1846 dump_queue_members(q);
1850 res = RES_OUTOFMEMORY;
1855 ast_mutex_unlock(&q->lock);
1858 ast_mutex_unlock(&q->lock);
1860 ast_mutex_unlock(&qlock);
1864 static int set_member_paused(char *queuename, char *interface, int paused)
1867 struct ast_call_queue *q;
1870 /* Special event for when all queues are paused - individual events still generated */
1872 if (ast_strlen_zero(queuename))
1873 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
1875 ast_mutex_lock(&qlock);
1876 for (q = queues ; q ; q = q->next) {
1877 ast_mutex_lock(&q->lock);
1878 if (ast_strlen_zero(queuename) || !strcmp(q->name, queuename)) {
1879 if ((mem = interface_exists(q, interface))) {
1881 if (mem->paused == paused)
1882 ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
1883 mem->paused = paused;
1885 if (queue_persistent_members)
1886 dump_queue_members(q);
1888 ast_queue_log(q->name, "NONE", interface, (paused ? "PAUSE" : "UNPAUSE"), "%s", "");
1890 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
1894 q->name, mem->interface, paused);
1897 ast_mutex_unlock(&q->lock);
1899 ast_mutex_unlock(&qlock);
1902 return RESULT_SUCCESS;
1904 return RESULT_FAILURE;
1907 /* Add members saved in the queue members DB file saves
1908 * created by dump_queue_members(), back into the queues */
1909 static void reload_queue_members(void)
1912 char *pm_queue_name;
1914 char *pm_penalty_tok;
1916 char *pm_paused_tok;
1918 struct ast_db_entry *pm_db_tree = NULL;
1919 int pm_family_len = 0;
1920 struct ast_call_queue *cur_queue = NULL;
1921 char queue_data[PM_MAX_LEN];
1923 pm_db_tree = ast_db_gettree(pm_family, NULL);
1925 pm_family_len = strlen(pm_family);
1926 ast_mutex_lock(&qlock);
1927 /* Each key in 'pm_family' is the name of a specific queue in which
1928 * we will reload members into. */
1929 while (pm_db_tree) {
1930 pm_queue_name = pm_db_tree->key+pm_family_len+2;
1934 ast_mutex_lock(&cur_queue->lock);
1936 if (strcmp(pm_queue_name, cur_queue->name) == 0)
1939 ast_mutex_unlock(&cur_queue->lock);
1941 cur_queue = cur_queue->next;
1945 /* If the queue no longer exists, remove it from the
1947 ast_db_del(pm_family, pm_queue_name);
1948 pm_db_tree = pm_db_tree->next;
1951 ast_mutex_unlock(&cur_queue->lock);
1953 if (!ast_db_get(pm_family, pm_queue_name, queue_data, PM_MAX_LEN)) {
1954 cur_pm_ptr = queue_data;
1955 while ((pm_interface = strsep(&cur_pm_ptr, ";"))) {
1956 /* On the last iteration, pm_interface is a pointer to an empty string. Don't report a spurious error. */
1957 if (pm_interface[0] == 0)
1959 if (!(pm_penalty_tok = strsep(&cur_pm_ptr, ";"))) {
1960 ast_log(LOG_WARNING, "Error parsing corrupted Queue DB string for '%s' (penalty)\n", pm_queue_name);
1963 pm_penalty = strtol(pm_penalty_tok, NULL, 10);
1964 if (errno == ERANGE) {
1965 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", pm_penalty_tok);
1969 /* If ptr[1] is ';', the string is 1 char long and can't be an interface */
1971 if (cur_pm_ptr[1] == ';') {
1972 if (!(pm_paused_tok = strsep(&cur_pm_ptr, ";"))) {
1973 ast_log(LOG_WARNING, "Error parsing corrupted Queue DB string for '%s' (paused)\n", pm_queue_name);
1976 pm_paused = strtol(pm_paused_tok, NULL, 10);
1977 if ((errno == ERANGE) || (pm_paused < 0 || pm_paused > 1)) {
1978 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", pm_paused_tok);
1981 } else if (option_debug)
1982 ast_verbose(VERBOSE_PREFIX_3 "Found old-format queue member %s:%s\n", pm_queue_name, pm_interface);
1985 ast_log(LOG_DEBUG, "Reload Members: Queue: %s Member: %s Penalty: %d Paused: %d\n", pm_queue_name, pm_interface, pm_penalty, pm_paused);
1987 if (add_to_queue(pm_queue_name, pm_interface, pm_penalty, pm_paused) == RES_OUTOFMEMORY) {
1988 ast_log(LOG_ERROR, "Out of Memory when loading queue member from astdb\n");
1994 pm_db_tree = pm_db_tree->next;
1997 ast_log(LOG_NOTICE, "Queue members sucessfully reloaded from database.\n");
1998 ast_mutex_unlock(&qlock);
2000 ast_db_freetree(pm_db_tree);
2005 static int pqm_exec(struct ast_channel *chan, void *data)
2007 struct localuser *u;
2008 char *queuename, *interface;
2011 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface])\n");
2015 queuename = ast_strdupa((char *)data);
2017 ast_log(LOG_ERROR, "Out of memory\n");
2021 interface = strchr(queuename, '|');
2023 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface])\n");
2032 if (set_member_paused(queuename, interface, 1)) {
2033 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", interface);
2034 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2035 chan->priority += 100;
2036 LOCAL_USER_REMOVE(u);
2042 LOCAL_USER_REMOVE(u);
2047 static int upqm_exec(struct ast_channel *chan, void *data)
2049 struct localuser *u;
2050 char *queuename, *interface;
2053 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface])\n");
2057 queuename = ast_strdupa((char *)data);
2059 ast_log(LOG_ERROR, "Out of memory\n");
2063 interface = strchr(queuename, '|');
2065 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface])\n");
2074 if (set_member_paused(queuename, interface, 0)) {
2075 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", interface);
2076 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2077 chan->priority += 100;
2078 LOCAL_USER_REMOVE(u);
2084 LOCAL_USER_REMOVE(u);
2089 static int rqm_exec(struct ast_channel *chan, void *data)
2092 struct localuser *u;
2093 char *info, *queuename;
2094 char tmpchan[256]="";
2095 char *interface = NULL;
2098 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface])\n");
2102 info = ast_strdupa((char *)data);
2104 ast_log(LOG_ERROR, "Out of memory\n");
2112 interface = strchr(queuename, '|');
2118 strncpy(tmpchan, chan->name, sizeof(tmpchan) - 1);
2119 interface = strrchr(tmpchan, '-');
2122 interface = tmpchan;
2126 switch (remove_from_queue(queuename, interface)) {
2128 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", interface, queuename);
2132 ast_log(LOG_WARNING, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
2133 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2134 chan->priority += 100;
2138 case RES_NOSUCHQUEUE:
2139 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", queuename);
2142 case RES_OUTOFMEMORY:
2143 ast_log(LOG_ERROR, "Out of memory\n");
2147 LOCAL_USER_REMOVE(u);
2151 static int aqm_exec(struct ast_channel *chan, void *data)
2154 struct localuser *u;
2157 char tmpchan[512]="";
2158 char *interface=NULL;
2159 char *penaltys=NULL;
2163 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface][|penalty]])\n");
2167 info = ast_strdupa((char *)data);
2169 ast_log(LOG_ERROR, "Out of memory\n");
2176 interface = strchr(queuename, '|');
2182 penaltys = strchr(interface, '|');
2188 if (!interface || ast_strlen_zero(interface)) {
2189 strncpy(tmpchan, chan->name, sizeof(tmpchan) - 1);
2190 interface = strrchr(tmpchan, '-');
2193 interface = tmpchan;
2195 if (penaltys && !ast_strlen_zero(penaltys)) {
2196 if ((sscanf(penaltys, "%d", &penalty) != 1) || penalty < 0) {
2197 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", penaltys);
2203 switch (add_to_queue(queuename, interface, penalty, 0)) {
2205 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", interface, queuename);
2209 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
2210 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2211 chan->priority += 100;
2215 case RES_NOSUCHQUEUE:
2216 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", queuename);
2219 case RES_OUTOFMEMORY:
2220 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", interface, queuename);
2224 LOCAL_USER_REMOVE(u);
2228 static int queue_exec(struct ast_channel *chan, void *data)
2232 struct localuser *u;
2235 char *info_ptr = info;
2236 char *options = NULL;
2238 char *announceoverride = NULL;
2239 char *user_priority;
2241 char *queuetimeoutstr = NULL;
2243 /* whether to exit Queue application after the timeout hits */
2246 /* Our queue entry */
2247 struct queue_ent qe;
2249 if (!data || ast_strlen_zero(data)) {
2250 ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL][|announceoverride][|timeout]]\n");
2256 /* Setup our queue entry */
2257 memset(&qe, 0, sizeof(qe));
2258 qe.start = time(NULL);
2260 /* Parse our arguments XXX Check for failure XXX */
2261 strncpy(info, (char *) data, sizeof(info) - 1);
2262 queuename = strsep(&info_ptr, "|");
2263 options = strsep(&info_ptr, "|");
2264 url = strsep(&info_ptr, "|");
2265 announceoverride = strsep(&info_ptr, "|");
2266 queuetimeoutstr = info_ptr;
2268 /* set the expire time based on the supplied timeout; */
2269 if (queuetimeoutstr)
2270 qe.expire = qe.start + atoi(queuetimeoutstr);
2274 /* Get the priority from the variable ${QUEUE_PRIO} */
2275 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
2276 if (user_priority) {
2277 if (sscanf(user_priority, "%d", &prio) == 1) {
2279 ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
2282 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
2283 user_priority, chan->name);
2287 if (option_debug > 2)
2288 ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n");
2293 if (strchr(options, 'r')) {
2299 ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
2300 queuename, options, url, announceoverride, (long)qe.expire, (int)prio);
2303 qe.prio = (int)prio;
2304 qe.last_pos_said = 0;
2306 if (!join_queue(queuename, &qe)) {
2307 ast_queue_log(queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", url ? url : "", chan->cid.cid_num ? chan->cid.cid_num : "");
2308 /* Start music on hold */
2311 ast_indicate(chan, AST_CONTROL_RINGING);
2313 ast_moh_start(chan, qe.moh);
2316 /* This is the wait loop for callers 2 through maxlen */
2318 res = wait_our_turn(&qe, ringing);
2319 /* If they hungup, return immediately */
2321 /* Record this abandoned call */
2322 record_abandoned(&qe);
2323 ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
2324 if (option_verbose > 2) {
2325 ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s while waiting their turn\n", queuename);
2332 if (valid_exit(&qe, res)) {
2333 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
2338 int makeannouncement = 0;
2340 /* This is the wait loop for the head caller*/
2341 /* To exit, they may get their call answered; */
2342 /* they may dial a digit from the queue context; */
2343 /* or, they may timeout. */
2345 /* Leave if we have exceeded our queuetimeout */
2346 if (qe.expire && (time(NULL) > qe.expire)) {
2351 if (makeannouncement) {
2352 /* Make a position announcement, if enabled */
2353 if (qe.parent->announcefrequency && !ringing)
2356 makeannouncement = 1;
2358 /* Try calling all queue members for 'timeout' seconds */
2359 res = try_calling(&qe, options, announceoverride, url, &go_on);
2363 ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
2365 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
2369 /* leave the queue if no agents, if enabled */
2370 if (ast_test_flag(qe.parent, QUEUE_FLAG_LEAVEWHENEMPTY) && has_no_members(qe.parent)) {
2375 /* Leave if we have exceeded our queuetimeout */
2376 if (qe.expire && (time(NULL) > qe.expire)) {
2381 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
2382 res = wait_a_bit(&qe);
2384 ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
2385 if (option_verbose > 2) {
2386 ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s when they almost made it\n", queuename);
2391 if (res && valid_exit(&qe, res)) {
2392 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
2395 /* exit after 'timeout' cycle if 'n' option enabled */
2397 if (option_verbose > 2) {
2398 ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n");
2401 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
2405 /* Since this is a priority queue and
2406 * it is not sure that we are still at the head
2407 * of the queue, go and check for our turn again.
2409 if (!is_our_turn(&qe)) {
2411 ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n",
2417 /* Don't allow return code > 0 */
2418 if (res >= 0 && res != AST_PBX_KEEPALIVE) {
2421 ast_indicate(chan, -1);
2425 ast_stopstream(chan);
2429 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", queuename);
2432 LOCAL_USER_REMOVE(u);
2436 static void reload_queues(void)
2438 struct ast_call_queue *q, *ql, *qn;
2439 struct ast_config *cfg;
2441 struct ast_variable *var;
2442 struct member *prev, *cur;
2444 char *general_val = NULL;
2446 cfg = ast_config_load("queues.conf");
2448 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
2451 ast_mutex_lock(&qlock);
2453 /* Mark all queues as dead for the moment */
2456 ast_set_flag(q, QUEUE_FLAG_DEAD);
2459 /* Chug through config file */
2460 cat = ast_category_browse(cfg, NULL);
2462 if (strcasecmp(cat, "general")) { /* Define queue */
2463 /* Look for an existing one */
2466 if (!strcmp(q->name, cat))
2472 q = malloc(sizeof(struct ast_call_queue));
2475 memset(q, 0, sizeof(struct ast_call_queue));
2476 ast_mutex_init(&q->lock);
2477 strncpy(q->name, cat, sizeof(q->name) - 1);
2484 ast_mutex_lock(&q->lock);
2485 /* Re-initialize the queue */
2486 ast_clear_flag(q, QUEUE_FLAG_DEAD);
2490 q->announcefrequency = 0;
2491 q->announceholdtime = 0;
2492 q->roundingseconds = 0; /* Default - don't announce seconds */
2494 q->callscompleted = 0;
2495 q->callsabandoned = 0;
2496 q->callscompletedinsl = 0;
2497 q->servicelevel = 0;
2501 q->announce[0] = '\0';
2502 q->context[0] = '\0';
2503 q->monfmt[0] = '\0';
2504 strncpy(q->sound_next, "queue-youarenext", sizeof(q->sound_next) - 1);
2505 strncpy(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare) - 1);
2506 strncpy(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls) - 1);
2507 strncpy(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime) - 1);
2508 strncpy(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes) - 1);
2509 strncpy(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds) - 1);
2510 strncpy(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks) - 1);
2511 strncpy(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan) - 1);
2512 strncpy(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold) - 1);
2515 /* find the end of any dynamic members */
2519 var = ast_variable_browse(cfg, cat);
2521 if (!strcasecmp(var->name, "member")) {
2522 /* Add a new member */
2523 cur = malloc(sizeof(struct member));
2525 memset(cur, 0, sizeof(struct member));
2526 strncpy(cur->interface, var->value, sizeof(cur->interface) - 1);
2527 if ((tmp = strchr(cur->interface, ','))) {
2530 cur->penalty = atoi(tmp);
2531 if (cur->penalty < 0)
2534 if (!strchr(cur->interface, '/'))
2535 ast_log(LOG_WARNING, "No location at line %d of queue.conf\n", var->lineno);
2542 } else if (!strcasecmp(var->name, "music") || !strcasecmp(var->name, "musiconhold")) {
2543 strncpy(q->moh, var->value, sizeof(q->moh) - 1);
2544 } else if (!strcasecmp(var->name, "announce")) {
2545 strncpy(q->announce, var->value, sizeof(q->announce) - 1);
2546 } else if (!strcasecmp(var->name, "context")) {
2547 strncpy(q->context, var->value, sizeof(q->context) - 1);
2548 } else if (!strcasecmp(var->name, "timeout")) {
2549 q->timeout = atoi(var->value);
2550 } else if (!strcasecmp(var->name, "monitor-join")) {
2551 ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_MONJOIN);
2552 } else if (!strcasecmp(var->name, "monitor-format")) {
2553 strncpy(q->monfmt, var->value, sizeof(q->monfmt) - 1);
2554 } else if (!strcasecmp(var->name, "queue-youarenext")) {
2555 strncpy(q->sound_next, var->value, sizeof(q->sound_next) - 1);
2556 } else if (!strcasecmp(var->name, "queue-thereare")) {
2557 strncpy(q->sound_thereare, var->value, sizeof(q->sound_thereare) - 1);
2558 } else if (!strcasecmp(var->name, "queue-callswaiting")) {
2559 strncpy(q->sound_calls, var->value, sizeof(q->sound_calls) - 1);
2560 } else if (!strcasecmp(var->name, "queue-holdtime")) {
2561 strncpy(q->sound_holdtime, var->value, sizeof(q->sound_holdtime) - 1);
2562 } else if (!strcasecmp(var->name, "queue-minutes")) {
2563 strncpy(q->sound_minutes, var->value, sizeof(q->sound_minutes) - 1);
2564 } else if (!strcasecmp(var->name, "queue-seconds")) {
2565 strncpy(q->sound_seconds, var->value, sizeof(q->sound_seconds) - 1);
2566 } else if (!strcasecmp(var->name, "queue-lessthan")) {
2567 strncpy(q->sound_lessthan, var->value, sizeof(q->sound_lessthan) - 1);
2568 } else if (!strcasecmp(var->name, "queue-thankyou")) {
2569 strncpy(q->sound_thanks, var->value, sizeof(q->sound_thanks) - 1);
2570 } else if (!strcasecmp(var->name, "queue-reporthold")) {
2571 strncpy(q->sound_reporthold, var->value, sizeof(q->sound_reporthold) - 1);
2572 } else if (!strcasecmp(var->name, "announce-frequency")) {
2573 q->announcefrequency = atoi(var->value);
2574 } else if (!strcasecmp(var->name, "announce-round-seconds")) {
2575 q->roundingseconds = atoi(var->value);
2576 if(q->roundingseconds>60 || q->roundingseconds<0) {
2577 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);
2578 q->roundingseconds=0;
2580 } else if (!strcasecmp(var->name, "announce-holdtime")) {
2581 q->announceholdtime = (!strcasecmp(var->value,"once")) ? 1 : ast_true(var->value);
2582 } else if (!strcasecmp(var->name, "retry")) {
2583 q->retry = atoi(var->value);
2584 } else if (!strcasecmp(var->name, "wrapuptime")) {
2585 q->wrapuptime = atoi(var->value);
2586 } else if (!strcasecmp(var->name, "maxlen")) {
2587 q->maxlen = atoi(var->value);
2588 } else if (!strcasecmp(var->name, "servicelevel")) {
2589 q->servicelevel= atoi(var->value);
2590 } else if (!strcasecmp(var->name, "strategy")) {
2591 q->strategy = strat2int(var->value);
2592 if (q->strategy < 0) {
2593 ast_log(LOG_WARNING, "'%s' isn't a valid strategy, using ringall instead\n", var->value);
2596 } else if (!strcasecmp(var->name, "joinempty")) {
2597 ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_JOINEMPTY);
2598 } else if (!strcasecmp(var->name, "leavewhenempty")) {
2599 ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_LEAVEWHENEMPTY);
2600 } else if (!strcasecmp(var->name, "eventwhencalled")) {
2601 ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_EVENTWHENCALLED);
2602 } else if (!strcasecmp(var->name, "reportholdtime")) {
2603 ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_REPORTHOLDTIME);
2604 } else if (!strcasecmp(var->name, "memberdelay")) {
2605 q->memberdelay = atoi(var->value);
2606 } else if (!strcasecmp(var->name, "weight")) {
2607 q->weight = atoi(var->value);
2611 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queue.conf\n", cat, var->name, var->lineno);
2616 q->retry = DEFAULT_RETRY;
2618 q->timeout = DEFAULT_TIMEOUT;
2622 ast_mutex_unlock(&q->lock);
2629 /* Initialize global settings */
2630 queue_persistent_members = 0;
2631 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
2632 queue_persistent_members = ast_true(general_val);
2634 cat = ast_category_browse(cfg, cat);
2636 ast_config_destroy(cfg);
2641 if (ast_test_flag(q, QUEUE_FLAG_DEAD)) {
2649 ast_log(LOG_WARNING, "XXX Leaking a little memory :( XXX\n");
2651 for (cur = q->members; cur; cur = cur->next)
2652 cur->status = ast_device_state(cur->interface);
2657 ast_mutex_unlock(&qlock);
2660 static char *status2str(int status, char *buf, int buflen)
2663 case AST_DEVICE_UNKNOWN:
2664 strncpy(buf, "unknown", buflen - 1);
2666 case AST_DEVICE_NOT_INUSE:
2667 strncpy(buf, "notinuse", buflen - 1);
2669 case AST_DEVICE_INUSE:
2670 strncpy(buf, "inuse", buflen - 1);
2672 case AST_DEVICE_BUSY:
2673 strncpy(buf, "busy", buflen - 1);
2675 case AST_DEVICE_INVALID:
2676 strncpy(buf, "invalid", buflen - 1);
2678 case AST_DEVICE_UNAVAILABLE:
2679 strncpy(buf, "unavailable", buflen - 1);
2682 snprintf(buf, buflen, "unknown status %d", status);
2687 static int __queues_show(int fd, int argc, char **argv, int queue_show)
2689 struct ast_call_queue *q;
2690 struct queue_ent *qe;
2695 char calls[80] = "";
2696 char tmpbuf[80] = "";
2700 if ((!queue_show && argc != 2) || (queue_show && argc != 3))
2701 return RESULT_SHOWUSAGE;
2702 ast_mutex_lock(&qlock);
2705 ast_mutex_unlock(&qlock);
2707 ast_cli(fd, "No such queue: %s.\n",argv[2]);
2709 ast_cli(fd, "No queues.\n");
2710 return RESULT_SUCCESS;
2713 ast_mutex_lock(&q->lock);
2715 if (strcasecmp(q->name, argv[2]) != 0) {
2716 ast_mutex_unlock(&q->lock);
2719 ast_cli(fd, "No such queue: %s.\n",argv[2]);
2726 snprintf(max, sizeof(max), "%d", q->maxlen);
2728 strncpy(max, "unlimited", sizeof(max) - 1);
2730 if(q->callscompleted > 0)
2731 sl = 100*((float)q->callscompletedinsl/(float)q->callscompleted);
2732 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",
2733 q->name, q->count, max, int2strat(q->strategy), q->holdtime, q->weight, q->callscompleted, q->callsabandoned,sl,q->servicelevel);
2735 ast_cli(fd, " Members: \n");
2736 for (mem = q->members; mem; mem = mem->next) {
2738 snprintf(max, sizeof(max) - 20, " with penalty %d", mem->penalty);
2742 strncat(max, " (dynamic)", sizeof(max) - strlen(max) - 1);
2744 strncat(max, " (paused)", sizeof(max) - strlen(max) - 1);
2746 snprintf(max + strlen(max), sizeof(max) - strlen(max), " (%s)", status2str(mem->status, tmpbuf, sizeof(tmpbuf)));
2748 snprintf(calls, sizeof(calls), " has taken %d calls (last was %ld secs ago)",
2749 mem->calls, (long)(time(NULL) - mem->lastcall));
2751 strncpy(calls, " has taken no calls yet", sizeof(calls) - 1);
2752 ast_cli(fd, " %s%s%s\n&quo