2 * Asterisk -- A telephony toolkit for Linux.
4 * True call queues with optional send URL on answer
6 * Copyright (C) 1999-2005, 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 'persistent_members=<1|0>' setting in the
18 * '[general]' category 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, nonexistent, 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"
127 " This application sets the following channel variable upon completion:\n"
128 " QUEUESTATUS The status of the call as a text string, one of\n"
129 " TIMEOUT | FULL | JOINEMPTY | LEAVEEMPTY | JOINUNAVAIL | LEAVEUNAVAIL\n";
131 static char *app_aqm = "AddQueueMember" ;
132 static char *app_aqm_synopsis = "Dynamically adds queue members" ;
133 static char *app_aqm_descrip =
134 " AddQueueMember(queuename[|interface[|penalty]]):\n"
135 "Dynamically adds interface to an existing queue.\n"
136 "If the interface is already in the queue and there exists an n+101 priority\n"
137 "then it will then jump to this priority. Otherwise it will return an error\n"
138 "Returns -1 if there is an error.\n"
139 "Example: AddQueueMember(techsupport|SIP/3000)\n"
142 static char *app_rqm = "RemoveQueueMember" ;
143 static char *app_rqm_synopsis = "Dynamically removes queue members" ;
144 static char *app_rqm_descrip =
145 " RemoveQueueMember(queuename[|interface]):\n"
146 "Dynamically removes interface to an existing queue\n"
147 "If the interface is NOT in the queue and there exists an n+101 priority\n"
148 "then it will then jump to this priority. Otherwise it will return an error\n"
149 "Returns -1 if there is an error.\n"
150 "Example: RemoveQueueMember(techsupport|SIP/3000)\n"
153 static char *app_pqm = "PauseQueueMember" ;
154 static char *app_pqm_synopsis = "Pauses a queue member" ;
155 static char *app_pqm_descrip =
156 " PauseQueueMember([queuename]|interface):\n"
157 "Pauses (blocks calls for) a queue member.\n"
158 "The given interface will be paused in the given queue. This prevents\n"
159 "any calls from being sent from the queue to the interface until it is\n"
160 "unpaused with UnpauseQueueMember or the manager interface. If no\n"
161 "queuename is given, the interface is paused in every queue it is a\n"
162 "member of. If the interface is not in the named queue, or if no queue\n"
163 "is given and the interface is not in any queue, it will jump to\n"
164 " priority n+101, if it exists. Returns -1 if the interface is not\n"
165 "found and no extension to jump to exists, 0 otherwise.\n"
166 "Example: PauseQueueMember(|SIP/3000)\n";
168 static char *app_upqm = "UnpauseQueueMember" ;
169 static char *app_upqm_synopsis = "Unpauses a queue member" ;
170 static char *app_upqm_descrip =
171 " UnpauseQueueMember([queuename]|interface):\n"
172 "Unpauses (resumes calls to) a queue member.\n"
173 "This is the counterpart to PauseQueueMember and operates exactly the\n"
174 "same way, except it unpauses instead of pausing the given interface.\n"
175 "Example: UnpauseQueueMember(|SIP/3000)\n";
177 /* Persistent Members astdb family */
178 static const char *pm_family = "/Queue/PersistentMembers";
179 /* The maximum lengh of each persistent member queue database entry */
180 #define PM_MAX_LEN 2048
182 /* queues.conf [general] option */
183 static int queue_persistent_members = 0;
185 /* queues.conf per-queue weight option */
186 static int use_weight = 0;
192 QUEUE_LEAVEEMPTY = 3,
193 QUEUE_JOINUNAVAIL = 4,
194 QUEUE_LEAVEUNAVAIL = 5,
199 enum queue_result id;
201 } queue_results[] = {
202 { QUEUE_UNKNOWN, "UNKNOWN" },
203 { QUEUE_TIMEOUT, "TIMEOUT" },
204 { QUEUE_JOINEMPTY,"JOINEMPTY" },
205 { QUEUE_LEAVEEMPTY, "LEAVEEMPTY" },
206 { QUEUE_JOINUNAVAIL, "JOINUNAVAIL" },
207 { QUEUE_LEAVEUNAVAIL, "LEAVEUNAVAIL" },
208 { QUEUE_FULL, "FULL" },
211 /* We define a custom "local user" structure because we
212 use it not only for keeping track of what is in use but
213 also for keeping track of who we're dialing. */
216 struct ast_channel *chan;
222 struct member *member;
223 struct localuser *next;
229 struct ast_call_queue *parent; /* What queue is our parent */
230 char moh[80]; /* Name of musiconhold to be used */
231 char announce[80]; /* Announcement to play for member when call is answered */
232 char context[80]; /* Context when user exits queue */
233 int pos; /* Where we are in the queue */
234 int prio; /* Our priority */
235 int last_pos_said; /* Last position we told the user */
236 time_t last_pos; /* Last time we told the user their position */
237 int opos; /* Where we started in the queue */
238 int handled; /* Whether our call was handled */
239 time_t start; /* When we started holding */
240 time_t expire; /* When this entry should expire (time out of queue) */
241 struct ast_channel *chan; /* Our channel */
242 struct queue_ent *next; /* The next queue entry */
246 char interface[80]; /* Technology/Location */
247 int penalty; /* Are we a last resort? */
248 int calls; /* Number of calls serviced by this member */
249 int dynamic; /* Are we dynamically added? */
250 int status; /* Status of queue member */
251 int paused; /* Are we paused (not accepting calls)? */
252 time_t lastcall; /* When last successful call was hungup */
253 struct member *next; /* Next member */
256 /* values used in multi-bit flags in ast_call_queue */
257 #define QUEUE_EMPTY_NORMAL 1
258 #define QUEUE_EMPTY_STRICT 2
259 #define ANNOUNCEHOLDTIME_ALWAYS 1
260 #define ANNOUNCEHOLDTIME_ONCE 2
262 struct ast_call_queue {
264 char name[80]; /* Name */
265 char moh[80]; /* Music On Hold class to be used */
266 char announce[80]; /* Announcement to play when call is answered */
267 char context[80]; /* Exit context */
268 unsigned int monjoin:1;
270 unsigned int joinempty:2;
271 unsigned int eventwhencalled:1;
272 unsigned int leavewhenempty:2;
273 unsigned int reportholdtime:1;
274 unsigned int wrapped:1;
275 unsigned int timeoutrestart:1;
276 unsigned int announceholdtime:2;
277 unsigned int strategy:3;
278 unsigned int maskmemberstatus:1;
279 int announcefrequency; /* How often to announce their position */
280 int roundingseconds; /* How many seconds do we round to? */
281 int holdtime; /* Current avg holdtime, based on recursive boxcar filter */
282 int callscompleted; /* Number of queue calls completed */
283 int callsabandoned; /* Number of queue calls abandoned */
284 int servicelevel; /* seconds setting for servicelevel*/
285 int callscompletedinsl; /* Number of calls answered with servicelevel*/
286 char monfmt[8]; /* Format to use when recording calls */
287 char sound_next[80]; /* Sound file: "Your call is now first in line" (def. queue-youarenext) */
288 char sound_thereare[80]; /* Sound file: "There are currently" (def. queue-thereare) */
289 char sound_calls[80]; /* Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting)*/
290 char sound_holdtime[80]; /* Sound file: "The current estimated total holdtime is" (def. queue-holdtime) */
291 char sound_minutes[80]; /* Sound file: "minutes." (def. queue-minutes) */
292 char sound_lessthan[80]; /* Sound file: "less-than" (def. queue-lessthan) */
293 char sound_seconds[80]; /* Sound file: "seconds." (def. queue-seconds) */
294 char sound_thanks[80]; /* Sound file: "Thank you for your patience." (def. queue-thankyou) */
295 char sound_reporthold[80]; /* Sound file: "Hold time" (def. queue-reporthold) */
297 int count; /* How many entries */
298 int maxlen; /* Max number of entries */
299 int wrapuptime; /* Wrapup Time */
301 int retry; /* Retry calling everyone after this amount of time */
302 int timeout; /* How long to wait for an answer */
303 int weight; /* Respective weight */
305 /* Queue strategy things */
306 int rrpos; /* Round Robin - position */
307 int memberdelay; /* Seconds to delay connecting member to caller */
309 struct member *members; /* Head of the list of members */
310 struct queue_ent *head; /* Head of the list of callers */
311 struct ast_call_queue *next; /* Next call queue */
314 static struct ast_call_queue *queues = NULL;
315 AST_MUTEX_DEFINE_STATIC(qlock);
317 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
321 for (i = 0; i < sizeof(queue_results) / sizeof(queue_results[0]); i++) {
322 if (queue_results[i].id == res) {
323 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
329 static char *int2strat(int strategy)
332 for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
333 if (strategy == strategies[x].strategy)
334 return strategies[x].name;
339 static int strat2int(char *strategy)
342 for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
343 if (!strcasecmp(strategy, strategies[x].name))
344 return strategies[x].strategy;
349 /* Insert the 'new' entry after the 'prev' entry of queue 'q' */
350 static inline void insert_entry(struct ast_call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
352 struct queue_ent *cur;
369 enum queue_member_status {
371 QUEUE_NO_REACHABLE_MEMBERS,
375 static enum queue_member_status get_member_status(const struct ast_call_queue *q)
377 struct member *member;
378 enum queue_member_status result = QUEUE_NO_MEMBERS;
380 for (member = q->members; member; member = member->next) {
381 switch (member->status) {
382 case AST_DEVICE_INVALID:
385 case AST_DEVICE_UNAVAILABLE:
386 result = QUEUE_NO_REACHABLE_MEMBERS;
401 static void *changethread(void *data)
403 struct ast_call_queue *q;
404 struct statechange *sc = data;
409 technology = ast_strdupa(sc->dev);
410 loc = strchr(technology, '/');
419 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d'\n", technology, loc, sc->state);
420 ast_mutex_lock(&qlock);
421 for (q = queues; q; q = q->next) {
422 ast_mutex_lock(&q->lock);
425 if (!strcasecmp(sc->dev, cur->interface)) {
426 if (cur->status != sc->state) {
427 cur->status = sc->state;
428 if (!q->maskmemberstatus) {
429 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
438 q->name, cur->interface, cur->dynamic ? "dynamic" : "static",
439 cur->penalty, cur->calls, cur->lastcall, cur->status, cur->paused);
445 ast_mutex_unlock(&q->lock);
447 ast_mutex_unlock(&qlock);
449 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d'\n", technology, loc, sc->state);
454 static int statechange_queue(const char *dev, int state, void *ign)
456 /* Avoid potential for deadlocks by spawning a new thread to handle
458 struct statechange *sc;
462 sc = malloc(sizeof(struct statechange) + strlen(dev) + 1);
465 strcpy(sc->dev, dev);
466 pthread_attr_init(&attr);
467 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
468 if (ast_pthread_create(&t, &attr, changethread, sc)) {
469 ast_log(LOG_WARNING, "Failed to create update thread!\n");
476 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
478 struct ast_call_queue *q;
479 struct queue_ent *cur, *prev = NULL;
484 ast_mutex_lock(&qlock);
485 for (q = queues; q; q = q->next) {
486 if (!strcasecmp(q->name, queuename)) {
487 enum queue_member_status stat;
488 /* This is our one */
489 ast_mutex_lock(&q->lock);
490 stat = get_member_status(q);
491 if (!q->joinempty && (stat == QUEUE_NO_MEMBERS))
492 *reason = QUEUE_JOINEMPTY;
493 else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS))
494 *reason = QUEUE_JOINUNAVAIL;
495 else if (q->maxlen && (q->count >= q->maxlen))
496 *reason = QUEUE_FULL;
498 /* There's space for us, put us at the right position inside
500 * Take into account the priority of the calling user */
505 /* We have higher priority than the current user, enter
506 * before him, after all the other users with priority
507 * higher or equal to our priority. */
508 if ((!inserted) && (qe->prio > cur->prio)) {
509 insert_entry(q, prev, qe, &pos);
516 /* No luck, join at the end of the queue */
518 insert_entry(q, prev, qe, &pos);
519 strncpy(qe->moh, q->moh, sizeof(qe->moh) - 1);
520 strncpy(qe->announce, q->announce, sizeof(qe->announce) - 1);
521 strncpy(qe->context, q->context, sizeof(qe->context) - 1);
524 manager_event(EVENT_FLAG_CALL, "Join",
525 "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\n",
527 qe->chan->cid.cid_num ? qe->chan->cid.cid_num : "unknown",
528 qe->chan->cid.cid_name ? qe->chan->cid.cid_name : "unknown",
529 q->name, qe->pos, q->count );
531 ast_log(LOG_NOTICE, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
534 ast_mutex_unlock(&q->lock);
538 ast_mutex_unlock(&qlock);
542 static void free_members(struct ast_call_queue *q, int all)
544 /* Free non-dynamic members */
545 struct member *curm, *next, *prev;
551 if (all || !curm->dynamic) {
563 static void destroy_queue(struct ast_call_queue *q)
565 struct ast_call_queue *cur, *prev = NULL;
567 ast_mutex_lock(&qlock);
568 for (cur = queues; cur; cur = cur->next) {
571 prev->next = cur->next;
578 ast_mutex_unlock(&qlock);
580 ast_mutex_destroy(&q->lock);
584 static int play_file(struct ast_channel *chan, char *filename)
588 ast_stopstream(chan);
589 res = ast_streamfile(chan, filename, chan->language);
592 res = ast_waitstream(chan, "");
597 ast_log(LOG_WARNING, "ast_streamfile failed on %s \n", chan->name);
600 ast_stopstream(chan);
605 static int say_position(struct queue_ent *qe)
607 int res = 0, avgholdmins, avgholdsecs;
610 /* Check to see if this is ludicrous -- if we just announced position, don't do it again*/
612 if ( (now - qe->last_pos) < 15 )
615 /* If either our position has changed, or we are over the freq timer, say position */
616 if ( (qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency) )
619 ast_moh_stop(qe->chan);
620 /* Say we're next, if we are */
622 res += play_file(qe->chan, qe->parent->sound_next);
625 res += play_file(qe->chan, qe->parent->sound_thereare);
626 res += ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */
627 res += play_file(qe->chan, qe->parent->sound_calls);
629 /* Round hold time to nearest minute */
630 avgholdmins = abs(( (qe->parent->holdtime + 30) - (now - qe->start) ) / 60);
632 /* If they have specified a rounding then round the seconds as well */
633 if(qe->parent->roundingseconds) {
634 avgholdsecs = (abs(( (qe->parent->holdtime + 30) - (now - qe->start) )) - 60 * avgholdmins) / qe->parent->roundingseconds;
635 avgholdsecs*= qe->parent->roundingseconds;
640 if (option_verbose > 2)
641 ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
643 /* If the hold time is >1 min, if it's enabled, and if it's not
644 supposed to be only once and we have already said it, say it */
645 if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) &&
646 (!(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE) && qe->last_pos)) {
647 res += play_file(qe->chan, qe->parent->sound_holdtime);
649 if (avgholdmins < 2) {
650 res += play_file(qe->chan, qe->parent->sound_lessthan);
651 res += ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, (char *)NULL);
653 res += ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, (char*) NULL);
654 res += play_file(qe->chan, qe->parent->sound_minutes);
657 res += ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, (char*) NULL);
658 res += play_file(qe->chan, qe->parent->sound_seconds);
664 /* Set our last_pos indicators */
666 qe->last_pos_said = qe->pos;
668 if (option_verbose > 2)
669 ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n", qe->chan->name, qe->parent->name, qe->pos);
670 res += play_file(qe->chan, qe->parent->sound_thanks);
671 ast_moh_start(qe->chan, qe->moh);
676 static void record_abandoned(struct queue_ent *qe)
678 ast_mutex_lock(&qe->parent->lock);
679 qe->parent->callsabandoned++;
680 ast_mutex_unlock(&qe->parent->lock);
683 static void recalc_holdtime(struct queue_ent *qe)
685 int oldvalue, newvalue;
687 /* Calculate holdtime using a recursive boxcar filter */
688 /* Thanks to SRT for this contribution */
689 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
691 newvalue = time(NULL) - qe->start;
693 ast_mutex_lock(&qe->parent->lock);
694 if (newvalue <= qe->parent->servicelevel)
695 qe->parent->callscompletedinsl++;
696 oldvalue = qe->parent->holdtime;
697 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newvalue) >> 2;
698 ast_mutex_unlock(&qe->parent->lock);
702 static void leave_queue(struct queue_ent *qe)
704 struct ast_call_queue *q;
705 struct queue_ent *cur, *prev = NULL;
711 ast_mutex_lock(&q->lock);
719 /* Take us out of the queue */
720 manager_event(EVENT_FLAG_CALL, "Leave",
721 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\n",
722 qe->chan->name, q->name, q->count);
724 ast_log(LOG_NOTICE, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
726 /* Take us out of the queue */
728 prev->next = cur->next;
732 /* Renumber the people after us in the queue based on a new count */
738 ast_mutex_unlock(&q->lock);
739 if (q->dead && !q->count) {
740 /* It's dead and nobody is in it, so kill it */
745 /* Hang up a list of outgoing calls */
746 static void hangupcalls(struct localuser *outgoing, struct ast_channel *exception)
748 struct localuser *oo;
751 /* Hangup any existing lines we have open */
752 if (outgoing->chan && (outgoing->chan != exception))
753 ast_hangup(outgoing->chan);
755 outgoing=outgoing->next;
760 static int update_status(struct ast_call_queue *q, struct member *member, int status)
764 /* Since a reload could have taken place, we have to traverse the list to
765 be sure it's still valid */
766 ast_mutex_lock(&q->lock);
770 cur->status = status;
771 if (!q->maskmemberstatus) {
772 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
781 q->name, cur->interface, cur->dynamic ? "dynamic" : "static",
782 cur->penalty, cur->calls, cur->lastcall, cur->status, cur->paused);
789 ast_mutex_unlock(&q->lock);
793 static int update_dial_status(struct ast_call_queue *q, struct member *member, int status)
795 if (status == AST_CAUSE_BUSY)
796 status = AST_DEVICE_BUSY;
797 else if (status == AST_CAUSE_UNREGISTERED)
798 status = AST_DEVICE_UNAVAILABLE;
799 else if (status == AST_CAUSE_NOSUCHDRIVER)
800 status = AST_DEVICE_INVALID;
802 status = AST_DEVICE_UNKNOWN;
803 return update_status(q, member, status);
806 /* traverse all defined queues which have calls waiting and contain this member
807 return 0 if no other queue has precedence (higher weight) or 1 if found */
808 static int compare_weight(struct ast_call_queue *rq, struct member *member)
810 struct ast_call_queue *q;
814 /* &qlock and &rq->lock already set by try_calling()
815 * to solve deadlock */
816 for (q = queues; q; q = q->next) {
817 if (q == rq) /* don't check myself, could deadlock */
819 ast_mutex_lock(&q->lock);
820 if (q->count && q->members) {
821 for (mem = q->members; mem; mem = mem->next) {
823 ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
824 if (q->weight > rq->weight) {
825 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, rq->name, rq->weight, rq->count);
832 ast_mutex_unlock(&q->lock);
836 ast_mutex_unlock(&qlock);
840 static int ring_entry(struct queue_ent *qe, struct localuser *tmp, int *busies)
847 if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
849 ast_log(LOG_DEBUG, "Wrapuptime not yet expired for %s\n", tmp->interface);
851 ast_cdr_busy(qe->chan->cdr);
857 if (tmp->member->paused) {
859 ast_log(LOG_DEBUG, "%s paused, can't receive call\n", tmp->interface);
861 ast_cdr_busy(qe->chan->cdr);
865 if (use_weight && compare_weight(qe->parent,tmp->member)) {
866 ast_log(LOG_DEBUG, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
868 ast_cdr_busy(qe->chan->cdr);
874 strncpy(tech, tmp->interface, sizeof(tech) - 1);
875 if ((location = strchr(tech, '/')))
880 /* Request the peer */
881 tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
882 if (!tmp->chan) { /* If we can't, just go on to the next call */
884 ast_log(LOG_NOTICE, "Unable to create channel of type '%s' for Queue\n", cur->tech);
887 ast_cdr_busy(qe->chan->cdr);
889 update_dial_status(qe->parent, tmp->member, status);
892 } else if (status != tmp->oldstatus)
893 update_dial_status(qe->parent, tmp->member, status);
895 tmp->chan->appl = "AppQueue";
896 tmp->chan->data = "(Outgoing Line)";
897 tmp->chan->whentohangup = 0;
898 if (tmp->chan->cid.cid_num)
899 free(tmp->chan->cid.cid_num);
900 tmp->chan->cid.cid_num = NULL;
901 if (tmp->chan->cid.cid_name)
902 free(tmp->chan->cid.cid_name);
903 tmp->chan->cid.cid_name = NULL;
904 if (tmp->chan->cid.cid_ani)
905 free(tmp->chan->cid.cid_ani);
906 tmp->chan->cid.cid_ani = NULL;
907 if (qe->chan->cid.cid_num)
908 tmp->chan->cid.cid_num = strdup(qe->chan->cid.cid_num);
909 if (qe->chan->cid.cid_name)
910 tmp->chan->cid.cid_name = strdup(qe->chan->cid.cid_name);
911 if (qe->chan->cid.cid_ani)
912 tmp->chan->cid.cid_ani = strdup(qe->chan->cid.cid_ani);
914 /* Inherit specially named variables from parent channel */
915 ast_channel_inherit_variables(qe->chan, tmp->chan);
917 /* Presense of ADSI CPE on outgoing channel follows ours */
918 tmp->chan->adsicpe = qe->chan->adsicpe;
920 /* Place the call, but don't wait on the answer */
921 res = ast_call(tmp->chan, location, 0);
923 /* Again, keep going even if there's an error */
925 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
926 else if (option_verbose > 2)
927 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface);
928 ast_hangup(tmp->chan);
934 if (qe->parent->eventwhencalled) {
935 manager_event(EVENT_FLAG_AGENT, "AgentCalled",
936 "AgentCalled: %s\r\n"
937 "ChannelCalling: %s\r\n"
939 "CallerIDName: %s\r\n"
943 tmp->interface, qe->chan->name,
944 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
945 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
946 qe->chan->context, qe->chan->exten, qe->chan->priority);
948 if (option_verbose > 2)
949 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface);
954 static int ring_one(struct queue_ent *qe, struct localuser *outgoing, int *busies)
956 struct localuser *cur;
957 struct localuser *best;
964 if (cur->stillgoing && /* Not already done */
965 !cur->chan && /* Isn't already going */
966 (!best || (cur->metric < bestmetric))) { /* We haven't found one yet, or it's better */
967 bestmetric = cur->metric;
973 if (!qe->parent->strategy) {
974 /* Ring everyone who shares this best metric (for ringall) */
977 if (cur->stillgoing && !cur->chan && (cur->metric <= bestmetric)) {
979 ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
980 ring_entry(qe, cur, busies);
985 /* Ring just the best channel */
987 ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric);
988 ring_entry(qe, best, busies);
991 } while (best && !best->chan);
994 ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n");
1000 static int store_next(struct queue_ent *qe, struct localuser *outgoing)
1002 struct localuser *cur;
1003 struct localuser *best;
1009 if (cur->stillgoing && /* Not already done */
1010 !cur->chan && /* Isn't already going */
1011 (!best || (cur->metric < bestmetric))) { /* We haven't found one yet, or it's better */
1012 bestmetric = cur->metric;
1018 /* Ring just the best channel */
1020 ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric);
1021 qe->parent->rrpos = best->metric % 1000;
1023 /* Just increment rrpos */
1024 if (qe->parent->wrapped) {
1025 /* No more channels, start over */
1026 qe->parent->rrpos = 0;
1028 /* Prioritize next entry */
1029 qe->parent->rrpos++;
1032 qe->parent->wrapped = 0;
1036 static int valid_exit(struct queue_ent *qe, char digit)
1040 if (ast_strlen_zero(qe->context))
1044 if (ast_exists_extension(qe->chan, qe->context, tmp, 1, qe->chan->cid.cid_num)) {
1045 strncpy(qe->chan->context, qe->context, sizeof(qe->chan->context) - 1);
1046 strncpy(qe->chan->exten, tmp, sizeof(qe->chan->exten) - 1);
1047 qe->chan->priority = 0;
1053 #define AST_MAX_WATCHERS 256
1055 #define BUILD_WATCHERS do { \
1062 /* Keep track of important channels */ \
1063 if (o->stillgoing) { \
1066 watchers[pos++] = o->chan; \
1075 static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser *outgoing, int *to, char *digit, int prebusies, int caller_disconnect)
1077 char *queue = qe->parent->name;
1078 struct localuser *o;
1082 int sentringing = 0;
1083 int numbusies = prebusies;
1087 struct ast_frame *f;
1088 struct localuser *peer = NULL;
1089 struct ast_channel *watchers[AST_MAX_WATCHERS];
1091 struct ast_channel *winner;
1092 struct ast_channel *in = qe->chan;
1094 while(*to && !peer) {
1096 if ((found < 0) && stillgoing && !qe->parent->strategy) {
1097 /* On "ringall" strategy we only move to the next penalty level
1098 when *all* ringing phones are done in the current penalty level */
1099 ring_one(qe, outgoing, &numbusies);
1103 if (numlines == (numbusies + numnochan)) {
1104 ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
1106 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan);
1111 winner = ast_waitfor_n(watchers, pos, to);
1114 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
1116 if (option_verbose > 2)
1117 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
1120 } else if (o->chan && (o->chan == winner)) {
1121 if (!ast_strlen_zero(o->chan->call_forward)) {
1122 char tmpchan[256]="";
1125 strncpy(tmpchan, o->chan->call_forward, sizeof(tmpchan) - 1);
1126 if ((stuff = strchr(tmpchan, '/'))) {
1131 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
1135 /* Before processing channel, go ahead and check for forwarding */
1136 if (option_verbose > 2)
1137 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
1138 /* Setup parameters */
1139 o->chan = ast_request(tech, in->nativeformats, stuff, &status);
1140 if (status != o->oldstatus)
1141 update_dial_status(qe->parent, o->member, status);
1143 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
1147 if (o->chan->cid.cid_num)
1148 free(o->chan->cid.cid_num);
1149 o->chan->cid.cid_num = NULL;
1150 if (o->chan->cid.cid_name)
1151 free(o->chan->cid.cid_name);
1152 o->chan->cid.cid_name = NULL;
1154 if (in->cid.cid_num) {
1155 o->chan->cid.cid_num = strdup(in->cid.cid_num);
1156 if (!o->chan->cid.cid_num)
1157 ast_log(LOG_WARNING, "Out of memory\n");
1159 if (in->cid.cid_name) {
1160 o->chan->cid.cid_name = strdup(in->cid.cid_name);
1161 if (!o->chan->cid.cid_name)
1162 ast_log(LOG_WARNING, "Out of memory\n");
1164 strncpy(o->chan->accountcode, in->accountcode, sizeof(o->chan->accountcode) - 1);
1165 o->chan->cdrflags = in->cdrflags;
1167 if (in->cid.cid_ani) {
1168 if (o->chan->cid.cid_ani)
1169 free(o->chan->cid.cid_ani);
1170 o->chan->cid.cid_ani = malloc(strlen(in->cid.cid_ani) + 1);
1171 if (o->chan->cid.cid_ani)
1172 strncpy(o->chan->cid.cid_ani, in->cid.cid_ani, strlen(in->cid.cid_ani) + 1);
1174 ast_log(LOG_WARNING, "Out of memory\n");
1176 if (o->chan->cid.cid_rdnis)
1177 free(o->chan->cid.cid_rdnis);
1178 if (!ast_strlen_zero(in->macroexten))
1179 o->chan->cid.cid_rdnis = strdup(in->macroexten);
1181 o->chan->cid.cid_rdnis = strdup(in->exten);
1182 if (ast_call(o->chan, tmpchan, 0)) {
1183 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
1185 ast_hangup(o->chan);
1190 /* Hangup the original channel now, in case we needed it */
1194 f = ast_read(winner);
1196 if (f->frametype == AST_FRAME_CONTROL) {
1197 switch(f->subclass) {
1198 case AST_CONTROL_ANSWER:
1199 /* This is our guy if someone answered. */
1201 if (option_verbose > 2)
1202 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
1206 case AST_CONTROL_BUSY:
1207 if (option_verbose > 2)
1208 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
1211 ast_cdr_busy(in->cdr);
1212 ast_hangup(o->chan);
1214 if (qe->parent->strategy) {
1215 if (qe->parent->timeoutrestart)
1217 ring_one(qe, outgoing, &numbusies);
1221 case AST_CONTROL_CONGESTION:
1222 if (option_verbose > 2)
1223 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
1226 ast_cdr_busy(in->cdr);
1227 ast_hangup(o->chan);
1229 if (qe->parent->strategy) {
1230 if (qe->parent->timeoutrestart)
1232 ring_one(qe, outgoing, &numbusies);
1236 case AST_CONTROL_RINGING:
1237 if (option_verbose > 2)
1238 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
1241 ast_indicate(in, AST_CONTROL_RINGING);
1246 case AST_CONTROL_OFFHOOK:
1247 /* Ignore going off hook */
1250 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
1256 ast_hangup(o->chan);
1258 if (qe->parent->strategy) {
1259 if (qe->parent->timeoutrestart)
1261 ring_one(qe, outgoing, &numbusies);
1270 if (f && (f->frametype != AST_FRAME_VOICE))
1271 printf("Frame type: %d, %d\n", f->frametype, f->subclass);
1272 else if (!f || (f->frametype != AST_FRAME_VOICE))
1273 printf("Hangup received on %s\n", in->name);
1275 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
1280 if (f && (f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) {
1281 if (option_verbose > 3)
1282 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
1286 if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass != '*') && valid_exit(qe, f->subclass)) {
1287 if (option_verbose > 3)
1288 ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass);
1294 if (!*to && (option_verbose > 2))
1295 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
1302 static int is_our_turn(struct queue_ent *qe)
1304 struct queue_ent *ch;
1307 /* Atomically read the parent head -- does not need a lock */
1308 ch = qe->parent->head;
1309 /* If we are now at the top of the head, break out */
1312 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
1316 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
1322 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
1326 /* This is the holding pen for callers 2 through maxlen */
1328 enum queue_member_status stat;
1330 if (is_our_turn(qe))
1333 /* If we have timed out, break out */
1334 if (qe->expire && (time(NULL) > qe->expire)) {
1335 *reason = QUEUE_TIMEOUT;
1339 stat = get_member_status(qe->parent);
1341 /* leave the queue if no agents, if enabled */
1342 if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
1343 *reason = QUEUE_LEAVEEMPTY;
1348 /* leave the queue if no reachable agents, if enabled */
1349 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
1350 *reason = QUEUE_LEAVEUNAVAIL;
1355 /* Make a position announcement, if enabled */
1356 if (qe->parent->announcefrequency && !ringing)
1359 /* Wait a second before checking again */
1360 res = ast_waitfordigit(qe->chan, RECHECK * 1000);
1367 static int update_queue(struct ast_call_queue *q, struct member *member)
1371 /* Since a reload could have taken place, we have to traverse the list to
1372 be sure it's still valid */
1373 ast_mutex_lock(&q->lock);
1376 if (member == cur) {
1377 time(&cur->lastcall);
1383 q->callscompleted++;
1384 ast_mutex_unlock(&q->lock);
1388 static int calc_metric(struct ast_call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct localuser *tmp)
1390 switch (q->strategy) {
1391 case QUEUE_STRATEGY_RINGALL:
1392 /* Everyone equal, except for penalty */
1393 tmp->metric = mem->penalty * 1000000;
1395 case QUEUE_STRATEGY_ROUNDROBIN:
1398 /* No more channels, start over */
1401 /* Prioritize next entry */
1407 case QUEUE_STRATEGY_RRMEMORY:
1408 if (pos < q->rrpos) {
1409 tmp->metric = 1000 + pos;
1412 /* Indicate there is another priority */
1416 tmp->metric += mem->penalty * 1000000;
1418 case QUEUE_STRATEGY_RANDOM:
1419 tmp->metric = rand() % 1000;
1420 tmp->metric += mem->penalty * 1000000;
1422 case QUEUE_STRATEGY_FEWESTCALLS:
1423 tmp->metric = mem->calls;
1424 tmp->metric += mem->penalty * 1000000;
1426 case QUEUE_STRATEGY_LEASTRECENT:
1430 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
1431 tmp->metric += mem->penalty * 1000000;
1434 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
1440 static int try_calling(struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *go_on)
1443 struct localuser *outgoing=NULL, *tmp = NULL;
1445 char restofit[AST_MAX_EXTENSION];
1446 char oldexten[AST_MAX_EXTENSION]="";
1447 char oldcontext[AST_MAX_EXTENSION]="";
1448 char queuename[256]="";
1450 char *monitorfilename;
1451 struct ast_channel *peer;
1452 struct ast_channel *which;
1453 struct localuser *lpeer;
1454 struct member *member;
1455 int res = 0, bridge = 0;
1458 char *announce = NULL;
1462 struct ast_bridge_config bridge_config;
1463 char nondataquality = 1;
1465 memset(&bridge_config, 0, sizeof(bridge_config));
1467 for (; options && *options; options++)
1470 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
1473 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
1479 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
1482 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
1485 if ((now - qe->start >= qe->parent->timeout))
1490 /* Hold the lock while we setup the outgoing calls */
1492 ast_mutex_lock(&qlock);
1493 ast_mutex_lock(&qe->parent->lock);
1495 ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n",
1497 strncpy(queuename, qe->parent->name, sizeof(queuename) - 1);
1499 cur = qe->parent->members;
1500 if (!ast_strlen_zero(qe->announce))
1501 announce = qe->announce;
1502 if (announceoverride && !ast_strlen_zero(announceoverride))
1503 announce = announceoverride;
1506 tmp = malloc(sizeof(*tmp));
1508 ast_mutex_unlock(&qe->parent->lock);
1510 ast_mutex_unlock(&qlock);
1511 ast_log(LOG_WARNING, "Out of memory\n");
1514 memset(tmp, 0, sizeof(*tmp));
1515 tmp->stillgoing = -1;
1518 ast_log(LOG_DEBUG, "Queue with URL=%s_\n", url);
1520 ast_log(LOG_DEBUG, "Simple queue (no URL)\n");
1523 tmp->member = cur; /* Never directly dereference! Could change on reload */
1524 tmp->oldstatus = cur->status;
1525 tmp->lastcall = cur->lastcall;
1526 strncpy(tmp->interface, cur->interface, sizeof(tmp->interface)-1);
1527 /* If we're dialing by extension, look at the extension to know what to dial */
1528 if ((newnum = strstr(tmp->interface, "/BYEXTENSION"))) {
1530 strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit) - 1);
1531 snprintf(newnum, sizeof(tmp->interface) - (newnum - tmp->interface), "%s%s", qe->chan->exten, restofit);
1533 ast_log(LOG_DEBUG, "Dialing by extension %s\n", tmp->interface);
1535 /* Special case: If we ring everyone, go ahead and ring them, otherwise
1536 just calculate their metric for the appropriate strategy */
1537 calc_metric(qe->parent, cur, x++, qe, tmp);
1538 /* Put them in the list of outgoing thingies... We're ready now.
1539 XXX If we're forcibly removed, these outgoing calls won't get
1541 tmp->next = outgoing;
1543 /* If this line is up, don't try anybody else */
1544 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
1549 if (qe->parent->timeout)
1550 to = qe->parent->timeout * 1000;
1553 ring_one(qe, outgoing, &numbusies);
1554 ast_mutex_unlock(&qe->parent->lock);
1556 ast_mutex_unlock(&qlock);
1557 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT));
1558 ast_mutex_lock(&qe->parent->lock);
1559 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
1560 store_next(qe, outgoing);
1562 ast_mutex_unlock(&qe->parent->lock);
1569 /* Musta gotten hung up */
1570 record_abandoned(qe);
1573 if (digit && valid_exit(qe, digit))
1576 /* Nobody answered, next please? */
1580 ast_log(LOG_DEBUG, "%s: Nobody answered.\n", qe->chan->name);
1584 /* Ah ha! Someone answered within the desired timeframe. Of course after this
1585 we will always return with -1 so that it is hung up properly after the
1588 if (!strcmp(qe->chan->type,"Zap"))
1589 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
1590 if (!strcmp(peer->type,"Zap"))
1591 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
1592 /* Update parameters for the queue */
1593 recalc_holdtime(qe);
1594 member = lpeer->member;
1595 hangupcalls(outgoing, peer);
1597 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
1599 res2 = ast_autoservice_start(qe->chan);
1601 if (qe->parent->memberdelay) {
1602 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
1603 res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
1605 if (!res2 && announce) {
1606 if (play_file(peer, announce))
1607 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", announce);
1609 if (!res2 && qe->parent->reportholdtime) {
1610 if (!play_file(peer, qe->parent->sound_reporthold)) {
1615 holdtime = abs((now - qe->start) / 60);
1617 play_file(peer, qe->parent->sound_lessthan);
1618 ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL);
1620 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
1621 play_file(peer, qe->parent->sound_minutes);
1625 res2 |= ast_autoservice_stop(qe->chan);
1626 if (peer->_softhangup) {
1627 /* Agent must have hung up */
1628 ast_log(LOG_WARNING, "Agent on %s hungup on the customer. They're going to be pissed.\n", peer->name);
1629 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "AGENTDUMP", "%s", "");
1630 if (qe->parent->eventwhencalled) {
1631 manager_event(EVENT_FLAG_AGENT, "AgentDump",
1636 queuename, qe->chan->uniqueid, peer->name, member->interface);
1641 /* Caller must have hung up just before being connected*/
1642 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
1643 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
1644 record_abandoned(qe);
1649 /* Stop music on hold */
1650 ast_moh_stop(qe->chan);
1651 /* If appropriate, log that we have a destination channel */
1653 ast_cdr_setdestchan(qe->chan->cdr, peer->name);
1654 /* Make sure channels are compatible */
1655 res = ast_channel_make_compatible(qe->chan, peer);
1657 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "SYSCOMPAT", "%s", "");
1658 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
1662 /* Begin Monitoring */
1663 if (qe->parent->monfmt && *qe->parent->monfmt) {
1664 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
1665 if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))
1669 if (monitorfilename)
1670 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 );
1672 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
1673 if (qe->parent->monjoin)
1674 ast_monitor_setjoinfiles(which, 1);
1676 /* Drop out of the queue at this point, to prepare for next caller */
1678 if (url && !ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
1680 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
1681 ast_channel_sendurl(peer, url);
1683 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "CONNECT", "%ld", (long)time(NULL) - qe->start);
1684 if (qe->parent->eventwhencalled)
1685 manager_event(EVENT_FLAG_AGENT, "AgentConnect",
1690 "Holdtime: %ld\r\n",
1691 queuename, qe->chan->uniqueid, peer->name, member->interface,
1692 (long)time(NULL) - qe->start);
1693 strncpy(oldcontext, qe->chan->context, sizeof(oldcontext) - 1);
1694 strncpy(oldexten, qe->chan->exten, sizeof(oldexten) - 1);
1697 bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
1699 if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
1700 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "TRANSFER", "%s|%s", qe->chan->exten, qe->chan->context);
1701 } else if (qe->chan->_softhangup) {
1702 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETECALLER", "%ld|%ld",
1703 (long)(callstart - qe->start), (long)(time(NULL) - callstart));
1704 if (qe->parent->eventwhencalled)
1705 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
1712 "Reason: caller\r\n",
1713 queuename, qe->chan->uniqueid, peer->name, member->interface,
1714 (long)(callstart - qe->start), (long)(time(NULL) - callstart));
1716 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETEAGENT", "%ld|%ld", (long)(callstart - qe->start), (long)(time(NULL) - callstart));
1717 if (qe->parent->eventwhencalled)
1718 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
1724 "Reason: agent\r\n",
1725 queuename, qe->chan->uniqueid, peer->name, (long)(callstart - qe->start),
1726 (long)(time(NULL) - callstart));
1729 if(bridge != AST_PBX_NO_HANGUP_PEER)
1731 update_queue(qe->parent, member);
1733 res = 1; /* JDG: bridge successfull, leave app_queue */
1735 res = bridge; /* bridge error, stay in the queue */
1738 hangupcalls(outgoing, NULL);
1742 static int wait_a_bit(struct queue_ent *qe)
1744 /* Don't need to hold the lock while we setup the outgoing calls */
1745 int retrywait = qe->parent->retry * 1000;
1747 return ast_waitfordigit(qe->chan, retrywait);
1750 static struct member * interface_exists(struct ast_call_queue *q, char *interface)
1755 for (mem = q->members; mem; mem = mem->next)
1756 if (!strcmp(interface, mem->interface))
1763 static struct member *create_queue_node(char *interface, int penalty, int paused)
1767 /* Add a new member */
1769 cur = malloc(sizeof(struct member));
1772 memset(cur, 0, sizeof(struct member));
1773 cur->penalty = penalty;
1774 cur->paused = paused;
1775 strncpy(cur->interface, interface, sizeof(cur->interface) - 1);
1776 if (!strchr(cur->interface, '/'))
1777 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
1778 cur->status = ast_device_state(interface);
1784 /* Dump all members in a specific queue to the databse
1786 * <pm_family>/<queuename> = <interface>;<penalty>;<paused>[|...]
1789 static void dump_queue_members(struct ast_call_queue *pm_queue)
1791 struct member *cur_member;
1792 char value[PM_MAX_LEN];
1796 memset(value, 0, sizeof(value));
1801 for (cur_member = pm_queue->members; cur_member; cur_member = cur_member->next) {
1802 if (!cur_member->dynamic)
1805 res = snprintf(value + value_len, sizeof(value) - value_len, "%s;%d;%d%s",
1806 cur_member->interface, cur_member->penalty, cur_member->paused,
1807 cur_member->next ? "|" : "");
1808 if (res != strlen(value + value_len)) {
1809 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
1815 if (value_len && !cur_member) {
1816 if (ast_db_put(pm_family, pm_queue->name, value))
1817 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
1819 /* Delete the entry if the queue is empty or there is an error */
1820 ast_db_del(pm_family, pm_queue->name);
1823 static int remove_from_queue(char *queuename, char *interface)
1825 struct ast_call_queue *q;
1826 struct member *last_member, *look;
1827 int res = RES_NOSUCHQUEUE;
1829 ast_mutex_lock(&qlock);
1830 for (q = queues ; q ; q = q->next) {
1831 ast_mutex_lock(&q->lock);
1832 if (!strcmp(q->name, queuename)) {
1833 if ((last_member = interface_exists(q, interface))) {
1834 if ((look = q->members) == last_member) {
1835 q->members = last_member->next;
1837 while (look != NULL) {
1838 if (look->next == last_member) {
1839 look->next = last_member->next;
1846 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
1849 q->name, last_member->interface);
1852 if (queue_persistent_members)
1853 dump_queue_members(q);
1859 ast_mutex_unlock(&q->lock);
1862 ast_mutex_unlock(&q->lock);
1864 ast_mutex_unlock(&qlock);
1868 static int add_to_queue(char *queuename, char *interface, int penalty, int paused, int dump)
1870 struct ast_call_queue *q;
1871 struct member *new_member;
1872 int res = RES_NOSUCHQUEUE;
1874 ast_mutex_lock(&qlock);
1875 for (q = queues ; q ; q = q->next) {
1876 ast_mutex_lock(&q->lock);
1877 if (!strcmp(q->name, queuename)) {
1878 if (interface_exists(q, interface) == NULL) {
1879 new_member = create_queue_node(interface, penalty, paused);
1881 if (new_member != NULL) {
1882 new_member->dynamic = 1;
1883 new_member->next = q->members;
1884 q->members = new_member;
1885 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
1888 "Membership: %s\r\n"
1890 "CallsTaken: %d\r\n"
1894 q->name, new_member->interface, new_member->dynamic ? "dynamic" : "static",
1895 new_member->penalty, new_member->calls, new_member->lastcall, new_member->status, new_member->paused);
1898 dump_queue_members(q);
1902 res = RES_OUTOFMEMORY;
1907 ast_mutex_unlock(&q->lock);
1910 ast_mutex_unlock(&q->lock);
1912 ast_mutex_unlock(&qlock);
1916 static int set_member_paused(char *queuename, char *interface, int paused)
1919 struct ast_call_queue *q;
1922 /* Special event for when all queues are paused - individual events still generated */
1924 if (ast_strlen_zero(queuename))
1925 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
1927 ast_mutex_lock(&qlock);
1928 for (q = queues ; q ; q = q->next) {
1929 ast_mutex_lock(&q->lock);
1930 if (ast_strlen_zero(queuename) || !strcmp(q->name, queuename)) {
1931 if ((mem = interface_exists(q, interface))) {
1933 if (mem->paused == paused)
1934 ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
1935 mem->paused = paused;
1937 if (queue_persistent_members)
1938 dump_queue_members(q);
1940 ast_queue_log(q->name, "NONE", interface, (paused ? "PAUSE" : "UNPAUSE"), "%s", "");
1942 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
1946 q->name, mem->interface, paused);
1949 ast_mutex_unlock(&q->lock);
1951 ast_mutex_unlock(&qlock);
1954 return RESULT_SUCCESS;
1956 return RESULT_FAILURE;
1959 /* Reload dynamic queue members persisted into the astdb */
1960 static void reload_queue_members(void)
1970 struct ast_db_entry *db_tree;
1971 struct ast_db_entry *entry;
1972 struct ast_call_queue *cur_queue;
1973 char queue_data[PM_MAX_LEN];
1975 ast_mutex_lock(&qlock);
1977 /* Each key in 'pm_family' is the name of a queue */
1978 db_tree = ast_db_gettree(pm_family, NULL);
1979 for (entry = db_tree; entry; entry = entry->next) {
1981 queue_name = entry->key + strlen(pm_family) + 2;
1985 ast_mutex_lock(&cur_queue->lock);
1986 if (!strcmp(queue_name, cur_queue->name))
1988 ast_mutex_unlock(&cur_queue->lock);
1989 cur_queue = cur_queue->next;
1993 /* If the queue no longer exists, remove it from the
1995 ast_db_del(pm_family, queue_name);
1998 ast_mutex_unlock(&cur_queue->lock);
2000 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN))
2003 cur_ptr = queue_data;
2004 while ((member = strsep(&cur_ptr, "|"))) {
2005 if (ast_strlen_zero(member))
2008 interface = strsep(&member, ";");
2009 penalty_tok = strsep(&member, ";");
2010 paused_tok = strsep(&member, ";");
2013 ast_log(LOG_WARNING, "Error parsing persisent member string for '%s' (penalty)\n", queue_name);
2016 penalty = strtol(penalty_tok, NULL, 10);
2017 if (errno == ERANGE) {
2018 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
2023 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
2026 paused = strtol(paused_tok, NULL, 10);
2027 if ((errno == ERANGE) || paused < 0 || paused > 1) {
2028 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
2033 ast_log(LOG_DEBUG, "Reload Members: Queue: %s Member: %s Penalty: %d Paused: %d\n", queue_name, interface, penalty, paused);
2035 if (add_to_queue(queue_name, interface, penalty, paused, 0) == RES_OUTOFMEMORY) {
2036 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
2042 ast_mutex_unlock(&qlock);
2044 ast_log(LOG_NOTICE, "Queue members sucessfully reloaded from database.\n");
2045 ast_db_freetree(db_tree);
2049 static int pqm_exec(struct ast_channel *chan, void *data)
2051 struct localuser *u;
2052 char *queuename, *interface;
2055 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface])\n");
2059 queuename = ast_strdupa((char *)data);
2061 ast_log(LOG_ERROR, "Out of memory\n");
2065 interface = strchr(queuename, '|');
2067 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface])\n");
2076 if (set_member_paused(queuename, interface, 1)) {
2077 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", interface);
2078 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2079 chan->priority += 100;
2080 LOCAL_USER_REMOVE(u);
2086 LOCAL_USER_REMOVE(u);
2091 static int upqm_exec(struct ast_channel *chan, void *data)
2093 struct localuser *u;
2094 char *queuename, *interface;
2097 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface])\n");
2101 queuename = ast_strdupa((char *)data);
2103 ast_log(LOG_ERROR, "Out of memory\n");
2107 interface = strchr(queuename, '|');
2109 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface])\n");
2118 if (set_member_paused(queuename, interface, 0)) {
2119 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", interface);
2120 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2121 chan->priority += 100;
2122 LOCAL_USER_REMOVE(u);
2128 LOCAL_USER_REMOVE(u);
2133 static int rqm_exec(struct ast_channel *chan, void *data)
2136 struct localuser *u;
2137 char *info, *queuename;
2138 char tmpchan[256]="";
2139 char *interface = NULL;
2142 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface])\n");
2146 info = ast_strdupa((char *)data);
2148 ast_log(LOG_ERROR, "Out of memory\n");
2156 interface = strchr(queuename, '|');
2162 strncpy(tmpchan, chan->name, sizeof(tmpchan) - 1);
2163 interface = strrchr(tmpchan, '-');
2166 interface = tmpchan;
2170 switch (remove_from_queue(queuename, interface)) {
2172 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", interface, queuename);
2176 ast_log(LOG_WARNING, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
2177 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2178 chan->priority += 100;
2182 case RES_NOSUCHQUEUE:
2183 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", queuename);
2186 case RES_OUTOFMEMORY:
2187 ast_log(LOG_ERROR, "Out of memory\n");
2191 LOCAL_USER_REMOVE(u);
2195 static int aqm_exec(struct ast_channel *chan, void *data)
2198 struct localuser *u;
2201 char tmpchan[512]="";
2202 char *interface=NULL;
2203 char *penaltys=NULL;
2207 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface][|penalty]])\n");
2211 info = ast_strdupa((char *)data);
2213 ast_log(LOG_ERROR, "Out of memory\n");
2220 interface = strchr(queuename, '|');
2226 penaltys = strchr(interface, '|');
2232 if (!interface || ast_strlen_zero(interface)) {
2233 strncpy(tmpchan, chan->name, sizeof(tmpchan) - 1);
2234 interface = strrchr(tmpchan, '-');
2237 interface = tmpchan;
2239 if (penaltys && !ast_strlen_zero(penaltys)) {
2240 if ((sscanf(penaltys, "%d", &penalty) != 1) || penalty < 0) {
2241 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", penaltys);
2247 switch (add_to_queue(queuename, interface, penalty, 0, queue_persistent_members)) {
2249 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", interface, queuename);
2253 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
2254 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2255 chan->priority += 100;
2259 case RES_NOSUCHQUEUE:
2260 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", queuename);
2263 case RES_OUTOFMEMORY:
2264 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", interface, queuename);
2268 LOCAL_USER_REMOVE(u);
2272 static int queue_exec(struct ast_channel *chan, void *data)
2276 struct localuser *u;
2279 char *info_ptr = info;
2280 char *options = NULL;
2282 char *announceoverride = NULL;
2283 char *user_priority;
2285 char *queuetimeoutstr = NULL;
2286 enum queue_result reason = QUEUE_UNKNOWN;
2288 /* whether to exit Queue application after the timeout hits */
2291 /* Our queue entry */
2292 struct queue_ent qe;
2294 if (!data || ast_strlen_zero(data)) {
2295 ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL][|announceoverride][|timeout]]\n");
2301 /* Setup our queue entry */
2302 memset(&qe, 0, sizeof(qe));
2303 qe.start = time(NULL);
2305 /* Parse our arguments XXX Check for failure XXX */
2306 strncpy(info, (char *) data, sizeof(info) - 1);
2307 queuename = strsep(&info_ptr, "|");
2308 options = strsep(&info_ptr, "|");
2309 url = strsep(&info_ptr, "|");
2310 announceoverride = strsep(&info_ptr, "|");
2311 queuetimeoutstr = info_ptr;
2313 /* set the expire time based on the supplied timeout; */
2314 if (queuetimeoutstr)
2315 qe.expire = qe.start + atoi(queuetimeoutstr);
2319 /* Get the priority from the variable ${QUEUE_PRIO} */
2320 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
2321 if (user_priority) {
2322 if (sscanf(user_priority, "%d", &prio) == 1) {
2324 ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
2327 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
2328 user_priority, chan->name);
2332 if (option_debug > 2)
2333 ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n");
2337 if (options && (strchr(options, 'r')))
2341 ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
2342 queuename, options, url, announceoverride, (long)qe.expire, (int)prio);
2345 qe.prio = (int)prio;
2346 qe.last_pos_said = 0;
2348 if (!join_queue(queuename, &qe, &reason)) {
2349 ast_queue_log(queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", url ? url : "",
2350 chan->cid.cid_num ? chan->cid.cid_num : "");
2353 ast_indicate(chan, AST_CONTROL_RINGING);
2355 ast_moh_start(chan, qe.moh);
2358 /* This is the wait loop for callers 2 through maxlen */
2360 res = wait_our_turn(&qe, ringing, &reason);
2361 /* If they hungup, return immediately */
2363 /* Record this abandoned call */
2364 record_abandoned(&qe);
2365 ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
2366 if (option_verbose > 2) {
2367 ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s while waiting their turn\n", queuename);
2374 if (valid_exit(&qe, res)) {
2375 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
2380 int makeannouncement = 0;
2382 /* This is the wait loop for the head caller*/
2383 /* To exit, they may get their call answered; */
2384 /* they may dial a digit from the queue context; */
2385 /* or, they may timeout. */
2387 enum queue_member_status stat;
2389 /* Leave if we have exceeded our queuetimeout */
2390 if (qe.expire && (time(NULL) > qe.expire)) {
2391 reason = QUEUE_TIMEOUT;
2396 if (makeannouncement) {
2397 /* Make a position announcement, if enabled */
2398 if (qe.parent->announcefrequency && !ringing)
2401 makeannouncement = 1;
2403 /* Try calling all queue members for 'timeout' seconds */
2404 res = try_calling(&qe, options, announceoverride, url, &go_on);
2408 ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
2410 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
2414 stat = get_member_status(qe.parent);
2416 /* leave the queue if no agents, if enabled */
2417 if (qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
2418 reason = QUEUE_LEAVEEMPTY;
2423 /* leave the queue if no reachable agents, if enabled */
2424 if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
2425 reason = QUEUE_LEAVEUNAVAIL;
2430 /* Leave if we have exceeded our queuetimeout */
2431 if (qe.expire && (time(NULL) > qe.expire)) {
2432 reason = QUEUE_TIMEOUT;
2437 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
2438 res = wait_a_bit(&qe);
2440 ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
2441 if (option_verbose > 2) {
2442 ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s when they almost made it\n", queuename);
2447 if (res && valid_exit(&qe, res)) {
2448 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
2451 /* exit after 'timeout' cycle if 'n' option enabled */
2453 if (option_verbose > 2) {
2454 ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n");
2457 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
2458 reason = QUEUE_TIMEOUT;
2462 /* Since this is a priority queue and
2463 * it is not sure that we are still at the head
2464 * of the queue, go and check for our turn again.
2466 if (!is_our_turn(&qe)) {
2468 ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n",
2474 /* Don't allow return code > 0 */
2475 if (res >= 0 && res != AST_PBX_KEEPALIVE) {
2478 ast_indicate(chan, -1);
2482 ast_stopstream(chan);
2485 if (reason != QUEUE_UNKNOWN)
2486 set_queue_result(chan, reason);
2488 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", queuename);
2489 set_queue_result(chan, reason);
2492 LOCAL_USER_REMOVE(u);
2496 static void reload_queues(void)
2498 struct ast_call_queue *q, *ql, *qn;
2499 struct ast_config *cfg;
2501 struct ast_variable *var;
2502 struct member *prev, *cur;
2504 char *general_val = NULL;
2506 cfg = ast_config_load("queues.conf");
2508 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
2511 ast_mutex_lock(&qlock);
2513 /* Mark all queues as dead for the moment */
2519 /* Chug through config file */
2520 cat = ast_category_browse(cfg, NULL);
2522 if (strcasecmp(cat, "general")) { /* Define queue */
2523 /* Look for an existing one */
2526 if (!strcmp(q->name, cat))
2532 q = malloc(sizeof(struct ast_call_queue));
2535 memset(q, 0, sizeof(struct ast_call_queue));
2536 ast_mutex_init(&q->lock);
2537 strncpy(q->name, cat, sizeof(q->name) - 1);
2544 ast_mutex_lock(&q->lock);
2545 /* Re-initialize the queue */
2547 q->retry = DEFAULT_RETRY;
2550 q->announcefrequency = 0;
2551 q->announceholdtime = 0;
2552 q->roundingseconds = 0; /* Default - don't announce seconds */
2554 q->callscompleted = 0;
2555 q->callsabandoned = 0;
2556 q->callscompletedinsl = 0;
2557 q->servicelevel = 0;
2561 q->announce[0] = '\0';
2562 q->context[0] = '\0';
2563 q->monfmt[0] = '\0';
2564 strncpy(q->sound_next, "queue-youarenext", sizeof(q->sound_next) - 1);
2565 strncpy(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare) - 1);
2566 strncpy(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls) - 1);
2567 strncpy(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime) - 1);
2568 strncpy(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes) - 1);
2569 strncpy(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds) - 1);
2570 strncpy(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks) - 1);
2571 strncpy(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan) - 1);
2572 strncpy(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold) - 1);
2575 /* find the end of any dynamic members */
2579 var = ast_variable_browse(cfg, cat);
2581 if (!strcasecmp(var->name, "member")) {
2582 /* Add a new member */
2583 cur = malloc(sizeof(struct member));
2585 memset(cur, 0, sizeof(struct member));
2586 strncpy(cur->interface, var->value, sizeof(cur->interface) - 1);
2587 if ((tmp = strchr(cur->interface, ','))) {
2590 cur->penalty = atoi(tmp);
2591 if (cur->penalty < 0)
2594 if (!strchr(cur->interface, '/'))
2595 ast_log(LOG_WARNING, "No location at line %d of queue.conf\n", var->lineno);
2602 } else if (!strcasecmp(var->name, "music") || !strcasecmp(var->name, "musiconhold")) {
2603 strncpy(q->moh, var->value, sizeof(q->moh) - 1);
2604 } else if (!strcasecmp(var->name, "announce")) {
2605 strncpy(q->announce, var->value, sizeof(q->announce) - 1);
2606 } else if (!strcasecmp(var->name, "context")) {
2607 strncpy(q->context, var->value, sizeof(q->context) - 1);
2608 } else if (!strcasecmp(var->name, "timeout")) {
2609 q->timeout = atoi(var->value);
2610 } else if (!strcasecmp(var->name, "monitor-join")) {
2611 q->monjoin = ast_true(var->value);
2612 } else if (!strcasecmp(var->name, "monitor-format")) {
2613 strncpy(q->monfmt, var->value, sizeof(q->monfmt) - 1);
2614 } else if (!strcasecmp(var->name, "queue-youarenext")) {
2615 strncpy(q->sound_next, var->value, sizeof(q->sound_next) - 1);
2616 } else if (!strcasecmp(var->name, "queue-thereare")) {
2617 strncpy(q->sound_thereare, var->value, sizeof(q->sound_thereare) - 1);
2618 } else if (!strcasecmp(var->name, "queue-callswaiting")) {
2619 strncpy(q->sound_calls, var->value, sizeof(q->sound_calls) - 1);
2620 } else if (!strcasecmp(var->name, "queue-holdtime")) {
2621 strncpy(q->sound_holdtime, var->value, sizeof(q->sound_holdtime) - 1);
2622 } else if (!strcasecmp(var->name, "queue-minutes")) {
2623 strncpy(q->sound_minutes, var->value, sizeof(q->sound_minutes) - 1);
2624 } else if (!strcasecmp(var->name, "queue-seconds")) {
2625 strncpy(q->sound_seconds, var->value, sizeof(q->sound_seconds) - 1);
2626 } else if (!strcasecmp(var->name, "queue-lessthan")) {
2627 strncpy(q->sound_lessthan, var->value, sizeof(q->sound_lessthan) - 1);
2628 } else if (!strcasecmp(var->name, "queue-thankyou")) {
2629 strncpy(q->sound_thanks, var->value, sizeof(q->sound_thanks) - 1);
2630 } else if (!strcasecmp(var->name, "queue-reporthold")) {
2631 strncpy(q->sound_reporthold, var->value, sizeof(q->sound_reporthold) - 1);
2632 } else if (!strcasecmp(var->name, "announce-frequency")) {
2633 q->announcefrequency = atoi(var->value);
2634 } else if (!strcasecmp(var->name, "announce-round-seconds")) {
2635 q->roundingseconds = atoi(var->value);
2636 if(q->roundingseconds>60 || q->roundingseconds<0) {
2637 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);
2638 q->roundingseconds=0;
2640 } else if (!strcasecmp(var->name, "announce-holdtime")) {
2641 if (!strcasecmp(var->value, "once"))
2642 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
2643 else if (ast_true(var->value))
2644 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
2646 q->announceholdtime = 0;
2647 } else if (!strcasecmp(var->name, "retry")) {
2648 q->retry = atoi(var->value);
2649 } else if (!strcasecmp(var->name, "wrapuptime")) {
2650 q->wrapuptime = atoi(var->value);
2651 } else if (!strcasecmp(var->name, "maxlen")) {
2652 q->maxlen = atoi(var->value);
2653 } else if (!strcasecmp(var->name, "servicelevel")) {
2654 q->servicelevel= atoi(var->value);
2655 } else if (!strcasecmp(var->name, "strategy")) {
2656 q->strategy = strat2int(var->value);
2657 if (q->strategy < 0) {
2658 ast_log(LOG_WARNING, "'%s' isn't a valid strategy, using ringall instead\n", var->value);
2661 } else if (!strcasecmp(var->name, "joinempty")) {
2662 if (!strcasecmp(var->value, "strict"))
2663 q->joinempty = QUEUE_EMPTY_STRICT;
2664 else if (ast_true(var->value))
2665 q->joinempty = QUEUE_EMPTY_NORMAL;
2668 } else if (!strcasecmp(var->name, "leavewhenempty")) {
2669 if (!strcasecmp(var->value, "strict"))
2670 q->leavewhenempty = QUEUE_EMPTY_STRICT;
2671 else if (ast_true(var->value))
2672 q->leavewhenempty = QUEUE_EMPTY_NORMAL;
2674 q->leavewhenempty = 0;
2675 } else if (!strcasecmp(var->name, "eventmemberstatus")) {
2676 q->maskmemberstatus = !ast_true(var->value);
2677 } else if (!strcasecmp(var->name, "eventwhencalled")) {
2678 q->eventwhencalled = ast_true(var->value);
2679 } else if (!strcasecmp(var->name, "reportholdtime")) {
2680 q->reportholdtime = ast_true(var->value);
2681 } else if (!strcasecmp(var->name, "memberdelay")) {
2682 q->memberdelay = atoi(var->value);
2683 } else if (!strcasecmp(var->name, "weight")) {
2684 q->weight = atoi(var->value);
2687 } else if (!strcasecmp(var->name, "timeoutrestart")) {
2688 q->timeoutrestart = ast_true(var->value);
2690 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queue.conf\n", cat, var->name, var->lineno);
2695 q->retry = DEFAULT_RETRY;
2697 q->timeout = DEFAULT_TIMEOUT;
2701 ast_mutex_unlock(&q->lock);
2708 /* Initialize global settings */
2709 queue_persistent_members = 0;
2710 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
2711 queue_persistent_members = ast_true(general_val);
2713 cat = ast_category_browse(cfg, cat);
2715 ast_config_destroy(cfg);
2728 ast_log(LOG_WARNING, "XXX Leaking a little memory :( XXX\n");
2730 for (cur = q->members; cur; cur = cur->next)
2731 cur->status = ast_device_state(cur->interface);
2736 ast_mutex_unlock(&qlock);
2739 static char *status2str(int status, char *buf, int buflen)
2742 case AST_DEVICE_UNKNOWN:
2743 strncpy(buf, "unknown", buflen - 1);
2745 case AST_DEVICE_NOT_INUSE:
2746 strncpy(buf, "notinuse", buflen - 1);
2748 case AST_DEVICE_INUSE:
2749 strncpy(buf, "inuse", buflen - 1);
2751 case AST_DEVICE_BUSY:
2752 strncpy(buf, "busy", buflen - 1);
2754 case AST_DEVICE_INVALID:
2755 strncpy(buf, "invalid", buflen - 1);
2757 case AST_DEVICE_UNAVAILABLE:
2758 strncpy(buf, "unavailable", buflen - 1);
2761 snprintf(buf, buflen, "unknown status %d", status);
2766 static int __queues_show(int fd, int argc, char **argv, int queue_show)
2768 struct ast_call_queue *q;
2769 struct queue_ent *qe;