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;
1739 char value[PM_MAX_LEN];
1743 memset(value, 0, sizeof(value));
1748 for (cur_member = pm_queue->members; cur_member; cur_member = cur_member->next) {
1749 if (!cur_member->dynamic)
1752 res = snprintf(value + value_len, sizeof(value) - value_len, "%s;%d;%d%s",
1753 cur_member->interface, cur_member->penalty, cur_member->paused,
1754 cur_member->next ? "|" : "");
1755 if (res != strlen(value + value_len)) {
1756 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
1762 if (value_len && !cur_member) {
1763 if (ast_db_put(pm_family, pm_queue->name, value))
1764 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
1766 /* Delete the entry if the queue is empty or there is an error */
1767 ast_db_del(pm_family, pm_queue->name);
1770 static int remove_from_queue(char *queuename, char *interface)
1772 struct ast_call_queue *q;
1773 struct member *last_member, *look;
1774 int res = RES_NOSUCHQUEUE;
1776 ast_mutex_lock(&qlock);
1777 for (q = queues ; q ; q = q->next) {
1778 ast_mutex_lock(&q->lock);
1779 if (!strcmp(q->name, queuename)) {
1780 if ((last_member = interface_exists(q, interface))) {
1781 if ((look = q->members) == last_member) {
1782 q->members = last_member->next;
1784 while (look != NULL) {
1785 if (look->next == last_member) {
1786 look->next = last_member->next;
1793 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
1796 q->name, last_member->interface);
1799 if (queue_persistent_members)
1800 dump_queue_members(q);
1806 ast_mutex_unlock(&q->lock);
1809 ast_mutex_unlock(&q->lock);
1811 ast_mutex_unlock(&qlock);
1815 static int add_to_queue(char *queuename, char *interface, int penalty, int paused, int dump)
1817 struct ast_call_queue *q;
1818 struct member *new_member;
1819 int res = RES_NOSUCHQUEUE;
1821 ast_mutex_lock(&qlock);
1822 for (q = queues ; q ; q = q->next) {
1823 ast_mutex_lock(&q->lock);
1824 if (!strcmp(q->name, queuename)) {
1825 if (interface_exists(q, interface) == NULL) {
1826 new_member = create_queue_node(interface, penalty, paused);
1828 if (new_member != NULL) {
1829 new_member->dynamic = 1;
1830 new_member->next = q->members;
1831 q->members = new_member;
1832 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
1835 "Membership: %s\r\n"
1837 "CallsTaken: %d\r\n"
1841 q->name, new_member->interface, new_member->dynamic ? "dynamic" : "static",
1842 new_member->penalty, new_member->calls, new_member->lastcall, new_member->status, new_member->paused);
1845 dump_queue_members(q);
1849 res = RES_OUTOFMEMORY;
1854 ast_mutex_unlock(&q->lock);
1857 ast_mutex_unlock(&q->lock);
1859 ast_mutex_unlock(&qlock);
1863 static int set_member_paused(char *queuename, char *interface, int paused)
1866 struct ast_call_queue *q;
1869 /* Special event for when all queues are paused - individual events still generated */
1871 if (ast_strlen_zero(queuename))
1872 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
1874 ast_mutex_lock(&qlock);
1875 for (q = queues ; q ; q = q->next) {
1876 ast_mutex_lock(&q->lock);
1877 if (ast_strlen_zero(queuename) || !strcmp(q->name, queuename)) {
1878 if ((mem = interface_exists(q, interface))) {
1880 if (mem->paused == paused)
1881 ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
1882 mem->paused = paused;
1884 if (queue_persistent_members)
1885 dump_queue_members(q);
1887 ast_queue_log(q->name, "NONE", interface, (paused ? "PAUSE" : "UNPAUSE"), "%s", "");
1889 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
1893 q->name, mem->interface, paused);
1896 ast_mutex_unlock(&q->lock);
1898 ast_mutex_unlock(&qlock);
1901 return RESULT_SUCCESS;
1903 return RESULT_FAILURE;
1906 /* Reload dynamic queue members persisted into the astdb */
1907 static void reload_queue_members(void)
1917 struct ast_db_entry *db_tree;
1918 struct ast_db_entry *entry;
1919 struct ast_call_queue *cur_queue;
1920 char queue_data[PM_MAX_LEN];
1922 ast_mutex_lock(&qlock);
1924 /* Each key in 'pm_family' is the name of a queue */
1925 db_tree = ast_db_gettree(pm_family, NULL);
1926 for (entry = db_tree; entry; entry = entry->next) {
1928 queue_name = entry->key + strlen(pm_family) + 2;
1932 ast_mutex_lock(&cur_queue->lock);
1933 if (!strcmp(queue_name, cur_queue->name))
1935 ast_mutex_unlock(&cur_queue->lock);
1936 cur_queue = cur_queue->next;
1940 /* If the queue no longer exists, remove it from the
1942 ast_db_del(pm_family, queue_name);
1945 ast_mutex_unlock(&cur_queue->lock);
1947 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN))
1950 cur_ptr = queue_data;
1951 while ((member = strsep(&cur_ptr, "|"))) {
1952 if (ast_strlen_zero(member))
1955 interface = strsep(&member, ";");
1956 penalty_tok = strsep(&member, ";");
1957 paused_tok = strsep(&member, ";");
1960 ast_log(LOG_WARNING, "Error parsing persisent member string for '%s' (penalty)\n", queue_name);
1963 penalty = strtol(penalty_tok, NULL, 10);
1964 if (errno == ERANGE) {
1965 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
1970 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
1973 paused = strtol(paused_tok, NULL, 10);
1974 if ((errno == ERANGE) || paused < 0 || paused > 1) {
1975 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
1980 ast_log(LOG_DEBUG, "Reload Members: Queue: %s Member: %s Penalty: %d Paused: %d\n", queue_name, interface, penalty, paused);
1982 if (add_to_queue(queue_name, interface, penalty, paused, 0) == RES_OUTOFMEMORY) {
1983 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
1989 ast_mutex_unlock(&qlock);
1991 ast_log(LOG_NOTICE, "Queue members sucessfully reloaded from database.\n");
1992 ast_db_freetree(db_tree);
1996 static int pqm_exec(struct ast_channel *chan, void *data)
1998 struct localuser *u;
1999 char *queuename, *interface;
2002 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface])\n");
2006 queuename = ast_strdupa((char *)data);
2008 ast_log(LOG_ERROR, "Out of memory\n");
2012 interface = strchr(queuename, '|');
2014 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface])\n");
2023 if (set_member_paused(queuename, interface, 1)) {
2024 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", interface);
2025 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2026 chan->priority += 100;
2027 LOCAL_USER_REMOVE(u);
2033 LOCAL_USER_REMOVE(u);
2038 static int upqm_exec(struct ast_channel *chan, void *data)
2040 struct localuser *u;
2041 char *queuename, *interface;
2044 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface])\n");
2048 queuename = ast_strdupa((char *)data);
2050 ast_log(LOG_ERROR, "Out of memory\n");
2054 interface = strchr(queuename, '|');
2056 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface])\n");
2065 if (set_member_paused(queuename, interface, 0)) {
2066 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", interface);
2067 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2068 chan->priority += 100;
2069 LOCAL_USER_REMOVE(u);
2075 LOCAL_USER_REMOVE(u);
2080 static int rqm_exec(struct ast_channel *chan, void *data)
2083 struct localuser *u;
2084 char *info, *queuename;
2085 char tmpchan[256]="";
2086 char *interface = NULL;
2089 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface])\n");
2093 info = ast_strdupa((char *)data);
2095 ast_log(LOG_ERROR, "Out of memory\n");
2103 interface = strchr(queuename, '|');
2109 strncpy(tmpchan, chan->name, sizeof(tmpchan) - 1);
2110 interface = strrchr(tmpchan, '-');
2113 interface = tmpchan;
2117 switch (remove_from_queue(queuename, interface)) {
2119 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", interface, queuename);
2123 ast_log(LOG_WARNING, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
2124 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2125 chan->priority += 100;
2129 case RES_NOSUCHQUEUE:
2130 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", queuename);
2133 case RES_OUTOFMEMORY:
2134 ast_log(LOG_ERROR, "Out of memory\n");
2138 LOCAL_USER_REMOVE(u);
2142 static int aqm_exec(struct ast_channel *chan, void *data)
2145 struct localuser *u;
2148 char tmpchan[512]="";
2149 char *interface=NULL;
2150 char *penaltys=NULL;
2154 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface][|penalty]])\n");
2158 info = ast_strdupa((char *)data);
2160 ast_log(LOG_ERROR, "Out of memory\n");
2167 interface = strchr(queuename, '|');
2173 penaltys = strchr(interface, '|');
2179 if (!interface || ast_strlen_zero(interface)) {
2180 strncpy(tmpchan, chan->name, sizeof(tmpchan) - 1);
2181 interface = strrchr(tmpchan, '-');
2184 interface = tmpchan;
2186 if (penaltys && !ast_strlen_zero(penaltys)) {
2187 if ((sscanf(penaltys, "%d", &penalty) != 1) || penalty < 0) {
2188 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", penaltys);
2194 switch (add_to_queue(queuename, interface, penalty, 0, queue_persistent_members)) {
2196 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", interface, queuename);
2200 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
2201 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2202 chan->priority += 100;
2206 case RES_NOSUCHQUEUE:
2207 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", queuename);
2210 case RES_OUTOFMEMORY:
2211 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", interface, queuename);
2215 LOCAL_USER_REMOVE(u);
2219 static int queue_exec(struct ast_channel *chan, void *data)
2223 struct localuser *u;
2226 char *info_ptr = info;
2227 char *options = NULL;
2229 char *announceoverride = NULL;
2230 char *user_priority;
2232 char *queuetimeoutstr = NULL;
2234 /* whether to exit Queue application after the timeout hits */
2237 /* Our queue entry */
2238 struct queue_ent qe;
2240 if (!data || ast_strlen_zero(data)) {
2241 ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL][|announceoverride][|timeout]]\n");
2247 /* Setup our queue entry */
2248 memset(&qe, 0, sizeof(qe));
2249 qe.start = time(NULL);
2251 /* Parse our arguments XXX Check for failure XXX */
2252 strncpy(info, (char *) data, sizeof(info) - 1);
2253 queuename = strsep(&info_ptr, "|");
2254 options = strsep(&info_ptr, "|");
2255 url = strsep(&info_ptr, "|");
2256 announceoverride = strsep(&info_ptr, "|");
2257 queuetimeoutstr = info_ptr;
2259 /* set the expire time based on the supplied timeout; */
2260 if (queuetimeoutstr)
2261 qe.expire = qe.start + atoi(queuetimeoutstr);
2265 /* Get the priority from the variable ${QUEUE_PRIO} */
2266 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
2267 if (user_priority) {
2268 if (sscanf(user_priority, "%d", &prio) == 1) {
2270 ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
2273 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
2274 user_priority, chan->name);
2278 if (option_debug > 2)
2279 ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n");
2284 if (strchr(options, 'r')) {
2290 ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
2291 queuename, options, url, announceoverride, (long)qe.expire, (int)prio);
2294 qe.prio = (int)prio;
2295 qe.last_pos_said = 0;
2297 if (!join_queue(queuename, &qe)) {
2298 ast_queue_log(queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", url ? url : "", chan->cid.cid_num ? chan->cid.cid_num : "");
2299 /* Start music on hold */
2302 ast_indicate(chan, AST_CONTROL_RINGING);
2304 ast_moh_start(chan, qe.moh);
2307 /* This is the wait loop for callers 2 through maxlen */
2309 res = wait_our_turn(&qe, ringing);
2310 /* If they hungup, return immediately */
2312 /* Record this abandoned call */
2313 record_abandoned(&qe);
2314 ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
2315 if (option_verbose > 2) {
2316 ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s while waiting their turn\n", queuename);
2323 if (valid_exit(&qe, res)) {
2324 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
2329 int makeannouncement = 0;
2331 /* This is the wait loop for the head caller*/
2332 /* To exit, they may get their call answered; */
2333 /* they may dial a digit from the queue context; */
2334 /* or, they may timeout. */
2336 /* Leave if we have exceeded our queuetimeout */
2337 if (qe.expire && (time(NULL) > qe.expire)) {
2342 if (makeannouncement) {
2343 /* Make a position announcement, if enabled */
2344 if (qe.parent->announcefrequency && !ringing)
2347 makeannouncement = 1;
2349 /* Try calling all queue members for 'timeout' seconds */
2350 res = try_calling(&qe, options, announceoverride, url, &go_on);
2354 ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
2356 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
2360 /* leave the queue if no agents, if enabled */
2361 if (ast_test_flag(qe.parent, QUEUE_FLAG_LEAVEWHENEMPTY) && has_no_members(qe.parent)) {
2366 /* Leave if we have exceeded our queuetimeout */
2367 if (qe.expire && (time(NULL) > qe.expire)) {
2372 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
2373 res = wait_a_bit(&qe);
2375 ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
2376 if (option_verbose > 2) {
2377 ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s when they almost made it\n", queuename);
2382 if (res && valid_exit(&qe, res)) {
2383 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
2386 /* exit after 'timeout' cycle if 'n' option enabled */
2388 if (option_verbose > 2) {
2389 ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n");
2392 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
2396 /* Since this is a priority queue and
2397 * it is not sure that we are still at the head
2398 * of the queue, go and check for our turn again.
2400 if (!is_our_turn(&qe)) {
2402 ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n",
2408 /* Don't allow return code > 0 */
2409 if (res >= 0 && res != AST_PBX_KEEPALIVE) {
2412 ast_indicate(chan, -1);
2416 ast_stopstream(chan);
2420 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", queuename);
2423 LOCAL_USER_REMOVE(u);
2427 static void reload_queues(void)
2429 struct ast_call_queue *q, *ql, *qn;
2430 struct ast_config *cfg;
2432 struct ast_variable *var;
2433 struct member *prev, *cur;
2435 char *general_val = NULL;
2437 cfg = ast_config_load("queues.conf");
2439 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
2442 ast_mutex_lock(&qlock);
2444 /* Mark all queues as dead for the moment */
2447 ast_set_flag(q, QUEUE_FLAG_DEAD);
2450 /* Chug through config file */
2451 cat = ast_category_browse(cfg, NULL);
2453 if (strcasecmp(cat, "general")) { /* Define queue */
2454 /* Look for an existing one */
2457 if (!strcmp(q->name, cat))
2463 q = malloc(sizeof(struct ast_call_queue));
2466 memset(q, 0, sizeof(struct ast_call_queue));
2467 ast_mutex_init(&q->lock);
2468 strncpy(q->name, cat, sizeof(q->name) - 1);
2475 ast_mutex_lock(&q->lock);
2476 /* Re-initialize the queue */
2477 ast_clear_flag(q, QUEUE_FLAG_DEAD);
2478 q->retry = DEFAULT_RETRY;
2481 q->announcefrequency = 0;
2482 q->announceholdtime = 0;
2483 q->roundingseconds = 0; /* Default - don't announce seconds */
2485 q->callscompleted = 0;
2486 q->callsabandoned = 0;
2487 q->callscompletedinsl = 0;
2488 q->servicelevel = 0;
2492 q->announce[0] = '\0';
2493 q->context[0] = '\0';
2494 q->monfmt[0] = '\0';
2495 strncpy(q->sound_next, "queue-youarenext", sizeof(q->sound_next) - 1);
2496 strncpy(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare) - 1);
2497 strncpy(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls) - 1);
2498 strncpy(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime) - 1);
2499 strncpy(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes) - 1);
2500 strncpy(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds) - 1);
2501 strncpy(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks) - 1);
2502 strncpy(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan) - 1);
2503 strncpy(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold) - 1);
2506 /* find the end of any dynamic members */
2510 var = ast_variable_browse(cfg, cat);
2512 if (!strcasecmp(var->name, "member")) {
2513 /* Add a new member */
2514 cur = malloc(sizeof(struct member));
2516 memset(cur, 0, sizeof(struct member));
2517 strncpy(cur->interface, var->value, sizeof(cur->interface) - 1);
2518 if ((tmp = strchr(cur->interface, ','))) {
2521 cur->penalty = atoi(tmp);
2522 if (cur->penalty < 0)
2525 if (!strchr(cur->interface, '/'))
2526 ast_log(LOG_WARNING, "No location at line %d of queue.conf\n", var->lineno);
2533 } else if (!strcasecmp(var->name, "music") || !strcasecmp(var->name, "musiconhold")) {
2534 strncpy(q->moh, var->value, sizeof(q->moh) - 1);
2535 } else if (!strcasecmp(var->name, "announce")) {
2536 strncpy(q->announce, var->value, sizeof(q->announce) - 1);
2537 } else if (!strcasecmp(var->name, "context")) {
2538 strncpy(q->context, var->value, sizeof(q->context) - 1);
2539 } else if (!strcasecmp(var->name, "timeout")) {
2540 q->timeout = atoi(var->value);
2541 } else if (!strcasecmp(var->name, "monitor-join")) {
2542 ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_MONJOIN);
2543 } else if (!strcasecmp(var->name, "monitor-format")) {
2544 strncpy(q->monfmt, var->value, sizeof(q->monfmt) - 1);
2545 } else if (!strcasecmp(var->name, "queue-youarenext")) {
2546 strncpy(q->sound_next, var->value, sizeof(q->sound_next) - 1);
2547 } else if (!strcasecmp(var->name, "queue-thereare")) {
2548 strncpy(q->sound_thereare, var->value, sizeof(q->sound_thereare) - 1);
2549 } else if (!strcasecmp(var->name, "queue-callswaiting")) {
2550 strncpy(q->sound_calls, var->value, sizeof(q->sound_calls) - 1);
2551 } else if (!strcasecmp(var->name, "queue-holdtime")) {
2552 strncpy(q->sound_holdtime, var->value, sizeof(q->sound_holdtime) - 1);
2553 } else if (!strcasecmp(var->name, "queue-minutes")) {
2554 strncpy(q->sound_minutes, var->value, sizeof(q->sound_minutes) - 1);
2555 } else if (!strcasecmp(var->name, "queue-seconds")) {
2556 strncpy(q->sound_seconds, var->value, sizeof(q->sound_seconds) - 1);
2557 } else if (!strcasecmp(var->name, "queue-lessthan")) {
2558 strncpy(q->sound_lessthan, var->value, sizeof(q->sound_lessthan) - 1);
2559 } else if (!strcasecmp(var->name, "queue-thankyou")) {
2560 strncpy(q->sound_thanks, var->value, sizeof(q->sound_thanks) - 1);
2561 } else if (!strcasecmp(var->name, "queue-reporthold")) {
2562 strncpy(q->sound_reporthold, var->value, sizeof(q->sound_reporthold) - 1);
2563 } else if (!strcasecmp(var->name, "announce-frequency")) {
2564 q->announcefrequency = atoi(var->value);
2565 } else if (!strcasecmp(var->name, "announce-round-seconds")) {
2566 q->roundingseconds = atoi(var->value);
2567 if(q->roundingseconds>60 || q->roundingseconds<0) {
2568 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);
2569 q->roundingseconds=0;
2571 } else if (!strcasecmp(var->name, "announce-holdtime")) {
2572 q->announceholdtime = (!strcasecmp(var->value,"once")) ? 1 : ast_true(var->value);
2573 } else if (!strcasecmp(var->name, "retry")) {
2574 q->retry = atoi(var->value);
2575 } else if (!strcasecmp(var->name, "wrapuptime")) {
2576 q->wrapuptime = atoi(var->value);
2577 } else if (!strcasecmp(var->name, "maxlen")) {
2578 q->maxlen = atoi(var->value);
2579 } else if (!strcasecmp(var->name, "servicelevel")) {
2580 q->servicelevel= atoi(var->value);
2581 } else if (!strcasecmp(var->name, "strategy")) {
2582 q->strategy = strat2int(var->value);
2583 if (q->strategy < 0) {
2584 ast_log(LOG_WARNING, "'%s' isn't a valid strategy, using ringall instead\n", var->value);
2587 } else if (!strcasecmp(var->name, "joinempty")) {
2588 ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_JOINEMPTY);
2589 } else if (!strcasecmp(var->name, "leavewhenempty")) {
2590 ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_LEAVEWHENEMPTY);
2591 } else if (!strcasecmp(var->name, "eventwhencalled")) {
2592 ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_EVENTWHENCALLED);
2593 } else if (!strcasecmp(var->name, "reportholdtime")) {
2594 ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_REPORTHOLDTIME);
2595 } else if (!strcasecmp(var->name, "memberdelay")) {
2596 q->memberdelay = atoi(var->value);
2597 } else if (!strcasecmp(var->name, "weight")) {
2598 q->weight = atoi(var->value);
2602 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queue.conf\n", cat, var->name, var->lineno);
2607 q->retry = DEFAULT_RETRY;
2609 q->timeout = DEFAULT_TIMEOUT;
2613 ast_mutex_unlock(&q->lock);
2620 /* Initialize global settings */
2621 queue_persistent_members = 0;
2622 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
2623 queue_persistent_members = ast_true(general_val);
2625 cat = ast_category_browse(cfg, cat);
2627 ast_config_destroy(cfg);
2632 if (ast_test_flag(q, QUEUE_FLAG_DEAD)) {
2640 ast_log(LOG_WARNING, "XXX Leaking a little memory :( XXX\n");
2642 for (cur = q->members; cur; cur = cur->next)
2643 cur->status = ast_device_state(cur->interface);
2648 ast_mutex_unlock(&qlock);
2651 static char *status2str(int status, char *buf, int buflen)
2654 case AST_DEVICE_UNKNOWN:
2655 strncpy(buf, "unknown", buflen - 1);
2657 case AST_DEVICE_NOT_INUSE:
2658 strncpy(buf, "notinuse", buflen - 1);
2660 case AST_DEVICE_INUSE:
2661 strncpy(buf, "inuse", buflen - 1);
2663 case AST_DEVICE_BUSY:
2664 strncpy(buf, "busy", buflen - 1);
2666 case AST_DEVICE_INVALID:
2667 strncpy(buf, "invalid", buflen - 1);
2669 case AST_DEVICE_UNAVAILABLE:
2670 strncpy(buf, "unavailable", buflen - 1);
2673 snprintf(buf, buflen, "unknown status %d", status);
2678 static int __queues_show(int fd, int argc, char **argv, int queue_show)
2680 struct ast_call_queue *q;
2681 struct queue_ent *qe;
2686 char calls[80] = "";
2687 char tmpbuf[80] = "";
2691 if ((!queue_show && argc != 2) || (queue_show && argc != 3))
2692 return RESULT_SHOWUSAGE;
2693 ast_mutex_lock(&qlock);
2696 ast_mutex_unlock(&qlock);
2698 ast_cli(fd, "No such queue: %s.\n",argv[2]);
2700 ast_cli(fd, "No queues.\n");
2701 return RESULT_SUCCESS;
2704 ast_mutex_lock(&q->lock);
2706 if (strcasecmp(q->name, argv[2]) != 0) {
2707 ast_mutex_unlock(&q->lock);
2710 ast_cli(fd, "No such queue: %s.\n",argv[2]);
2717 snprintf(max, sizeof(max), "%d", q->maxlen);
2719 strncpy(max, "unlimited", sizeof(max) - 1);
2721 if(q->callscompleted > 0)
2722 sl = 100*((float)q->callscompletedinsl/(float)q->callscompleted);
2723 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",
2724 q->name, q->count, max, int2strat(q->strategy), q->holdtime, q->weight, q->callscompleted, q->callsabandoned,sl,q->servicelevel);
2726 ast_cli(fd, " Members: \n");
2727 for (mem = q->members; mem; mem = mem->next) {
2729 snprintf(max, sizeof(max) - 20, " with penalty %d", mem->penalty);
2733 strncat(max, " (dynamic)", sizeof(max) - strlen(max) - 1);
2735 strncat(max, " (paused)", sizeof(max) - strlen(max) - 1);
2737 snprintf(max + strlen(max), sizeof(max) - strlen(max), " (%s)", status2str(mem->status, tmpbuf, sizeof(tmpbuf)));
2739 snprintf(calls, sizeof(calls), " has taken %d calls (last was %ld secs ago)",
2740 mem->calls, (long)(time(NULL) - mem->lastcall));
2742 strncpy(calls, " has taken no calls yet", sizeof(calls) - 1);
2743 ast_cli(fd, " %s%s%s\n", mem->interface, max, calls);
2746 ast_cli(fd, " No Members\n");
2749 ast_cli(fd, " Callers: \n");
2750 for (qe = q->head; qe; qe = qe->next)
2751 ast_cli(fd, " %d. %s (wait: %ld:%2.2ld, prio: %d)\n", pos++, qe->chan->name,
2752 (long)(now - qe->start) / 60, (long)(now - qe->start) % 60, qe->prio);
2754 ast_cli(fd, " No Callers\n");
2756 ast_mutex_unlock(&q->lock);