Let's also include aclocal.m4
[asterisk-bristuff.git] / apps / app_queue.c
blobb8267ae0932a6ad947626d0c54d9ebf5a46bd0d2
1 /*
2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
19 /*! \file
21 * \brief True call queues with optional send URL on answer
23 * \author Mark Spencer <markster@digium.com>
25 * \arg Config in \ref Config_qu queues.conf
27 * \par Development notes
28 * \note 2004-11-25: Persistent Dynamic Members added by:
29 * NetNation Communications (www.netnation.com)
30 * Kevin Lindsay <kevinl@netnation.com>
32 * Each dynamic agent in each queue is now stored in the astdb.
33 * When asterisk is restarted, each agent will be automatically
34 * readded into their recorded queues. This feature can be
35 * configured with the 'persistent_members=<1|0>' setting in the
36 * '[general]' category in queues.conf. The default is on.
38 * \note 2004-06-04: Priorities in queues added by inAccess Networks (work funded by Hellas On Line (HOL) www.hol.gr).
40 * \note These features added by David C. Troy <dave@toad.net>:
41 * - Per-queue holdtime calculation
42 * - Estimated holdtime announcement
43 * - Position announcement
44 * - Abandoned/completed call counters
45 * - Failout timer passed as optional app parameter
46 * - Optional monitoring of calls, started when call is answered
48 * Patch Version 1.07 2003-12-24 01
50 * Added servicelevel statistic by Michiel Betel <michiel@betel.nl>
51 * Added Priority jumping code for adding and removing queue members by Jonathan Stanton <asterisk@doilooklikeicare.com>
53 * Fixed to work with CVS as of 2004-02-25 and released as 1.07a
54 * by Matthew Enger <m.enger@xi.com.au>
56 * \ingroup applications
59 /*** MODULEINFO
60 <depend>res_monitor</depend>
61 ***/
63 #include "asterisk.h"
65 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
67 #include <stdlib.h>
68 #include <errno.h>
69 #include <unistd.h>
70 #include <string.h>
71 #include <stdlib.h>
72 #include <stdio.h>
73 #include <sys/time.h>
74 #include <sys/signal.h>
75 #include <netinet/in.h>
77 #include "asterisk/lock.h"
78 #include "asterisk/file.h"
79 #include "asterisk/logger.h"
80 #include "asterisk/channel.h"
81 #include "asterisk/pbx.h"
82 #include "asterisk/options.h"
83 #include "asterisk/app.h"
84 #include "asterisk/linkedlists.h"
85 #include "asterisk/module.h"
86 #include "asterisk/translate.h"
87 #include "asterisk/say.h"
88 #include "asterisk/features.h"
89 #include "asterisk/musiconhold.h"
90 #include "asterisk/cli.h"
91 #include "asterisk/manager.h"
92 #include "asterisk/config.h"
93 #include "asterisk/monitor.h"
94 #include "asterisk/utils.h"
95 #include "asterisk/causes.h"
96 #include "asterisk/astdb.h"
97 #include "asterisk/devicestate.h"
98 #include "asterisk/stringfields.h"
99 #include "asterisk/astobj2.h"
100 #include "asterisk/global_datastores.h"
102 /* Please read before modifying this file.
103 * There are three locks which are regularly used
104 * throughout this file, the queue list lock, the lock
105 * for each individual queue, and the interface list lock.
106 * Please be extra careful to always lock in the following order
107 * 1) queue list lock
108 * 2) individual queue lock
109 * 3) interface list lock
110 * This order has sort of "evolved" over the lifetime of this
111 * application, but it is now in place this way, so please adhere
112 * to this order!
116 enum {
117 QUEUE_STRATEGY_RINGALL = 0,
118 QUEUE_STRATEGY_ROUNDROBIN,
119 QUEUE_STRATEGY_LEASTRECENT,
120 QUEUE_STRATEGY_FEWESTCALLS,
121 QUEUE_STRATEGY_RANDOM,
122 QUEUE_STRATEGY_RRMEMORY
125 static struct strategy {
126 int strategy;
127 char *name;
128 } strategies[] = {
129 { QUEUE_STRATEGY_RINGALL, "ringall" },
130 { QUEUE_STRATEGY_ROUNDROBIN, "roundrobin" },
131 { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
132 { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
133 { QUEUE_STRATEGY_RANDOM, "random" },
134 { QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
137 #define DEFAULT_RETRY 5
138 #define DEFAULT_TIMEOUT 15
139 #define RECHECK 1 /* Recheck every second to see we we're at the top yet */
140 #define MAX_PERIODIC_ANNOUNCEMENTS 10 /* The maximum periodic announcements we can have */
142 #define RES_OKAY 0 /* Action completed */
143 #define RES_EXISTS (-1) /* Entry already exists */
144 #define RES_OUTOFMEMORY (-2) /* Out of memory */
145 #define RES_NOSUCHQUEUE (-3) /* No such queue */
146 #define RES_NOT_DYNAMIC (-4) /* Member is not dynamic */
148 static char *app = "Queue";
150 static char *synopsis = "Queue a call for a call queue";
152 static char *descrip =
153 " Queue(queuename[|options[|URL][|announceoverride][|timeout][|AGI]):\n"
154 "Queues an incoming call in a particular call queue as defined in queues.conf.\n"
155 "This application will return to the dialplan if the queue does not exist, or\n"
156 "any of the join options cause the caller to not enter the queue.\n"
157 "The option string may contain zero or more of the following characters:\n"
158 " 'd' -- data-quality (modem) call (minimum delay).\n"
159 " 'h' -- allow callee to hang up by hitting *.\n"
160 " 'H' -- allow caller to hang up by hitting *.\n"
161 " 'n' -- no retries on the timeout; will exit this application and \n"
162 " go to the next step.\n"
163 " 'i' -- ignore call forward requests from queue members and do nothing\n"
164 " when they are requested.\n"
165 " 'r' -- ring instead of playing MOH\n"
166 " 't' -- allow the called user transfer the calling user\n"
167 " 'T' -- to allow the calling user to transfer the call.\n"
168 " 'w' -- allow the called user to write the conversation to disk via Monitor\n"
169 " 'W' -- allow the calling user to write the conversation to disk via Monitor\n"
170 " In addition to transferring the call, a call may be parked and then picked\n"
171 "up by another user.\n"
172 " The optional URL will be sent to the called party if the channel supports\n"
173 "it.\n"
174 " The optional AGI parameter will setup an AGI script to be executed on the \n"
175 "calling party's channel once they are connected to a queue member.\n"
176 " The timeout will cause the queue to fail out after a specified number of\n"
177 "seconds, checked between each queues.conf 'timeout' and 'retry' cycle.\n"
178 " This application sets the following channel variable upon completion:\n"
179 " QUEUESTATUS The status of the call as a text string, one of\n"
180 " TIMEOUT | FULL | JOINEMPTY | LEAVEEMPTY | JOINUNAVAIL | LEAVEUNAVAIL\n";
182 static char *app_aqm = "AddQueueMember" ;
183 static char *app_aqm_synopsis = "Dynamically adds queue members" ;
184 static char *app_aqm_descrip =
185 " AddQueueMember(queuename[|interface[|penalty[|options[|membername]]]]):\n"
186 "Dynamically adds interface to an existing queue.\n"
187 "If the interface is already in the queue and there exists an n+101 priority\n"
188 "then it will then jump to this priority. Otherwise it will return an error\n"
189 "The option string may contain zero or more of the following characters:\n"
190 " 'j' -- jump to +101 priority when appropriate.\n"
191 " This application sets the following channel variable upon completion:\n"
192 " AQMSTATUS The status of the attempt to add a queue member as a \n"
193 " text string, one of\n"
194 " ADDED | MEMBERALREADY | NOSUCHQUEUE \n"
195 "Example: AddQueueMember(techsupport|SIP/3000)\n"
198 static char *app_rqm = "RemoveQueueMember" ;
199 static char *app_rqm_synopsis = "Dynamically removes queue members" ;
200 static char *app_rqm_descrip =
201 " RemoveQueueMember(queuename[|interface[|options]]):\n"
202 "Dynamically removes interface to an existing queue\n"
203 "If the interface is NOT in the queue and there exists an n+101 priority\n"
204 "then it will then jump to this priority. Otherwise it will return an error\n"
205 "The option string may contain zero or more of the following characters:\n"
206 " 'j' -- jump to +101 priority when appropriate.\n"
207 " This application sets the following channel variable upon completion:\n"
208 " RQMSTATUS The status of the attempt to remove a queue member as a\n"
209 " text string, one of\n"
210 " REMOVED | NOTINQUEUE | NOSUCHQUEUE \n"
211 "Example: RemoveQueueMember(techsupport|SIP/3000)\n"
214 static char *app_pqm = "PauseQueueMember" ;
215 static char *app_pqm_synopsis = "Pauses a queue member" ;
216 static char *app_pqm_descrip =
217 " PauseQueueMember([queuename]|interface[|options]):\n"
218 "Pauses (blocks calls for) a queue member.\n"
219 "The given interface will be paused in the given queue. This prevents\n"
220 "any calls from being sent from the queue to the interface until it is\n"
221 "unpaused with UnpauseQueueMember or the manager interface. If no\n"
222 "queuename is given, the interface is paused in every queue it is a\n"
223 "member of. If the interface is not in the named queue, or if no queue\n"
224 "is given and the interface is not in any queue, it will jump to\n"
225 "priority n+101, if it exists and the appropriate options are set.\n"
226 "The application will fail if the interface is not found and no extension\n"
227 "to jump to exists.\n"
228 "The option string may contain zero or more of the following characters:\n"
229 " 'j' -- jump to +101 priority when appropriate.\n"
230 " This application sets the following channel variable upon completion:\n"
231 " PQMSTATUS The status of the attempt to pause a queue member as a\n"
232 " text string, one of\n"
233 " PAUSED | NOTFOUND\n"
234 "Example: PauseQueueMember(|SIP/3000)\n";
236 static char *app_upqm = "UnpauseQueueMember" ;
237 static char *app_upqm_synopsis = "Unpauses a queue member" ;
238 static char *app_upqm_descrip =
239 " UnpauseQueueMember([queuename]|interface[|options]):\n"
240 "Unpauses (resumes calls to) a queue member.\n"
241 "This is the counterpart to PauseQueueMember and operates exactly the\n"
242 "same way, except it unpauses instead of pausing the given interface.\n"
243 "The option string may contain zero or more of the following characters:\n"
244 " 'j' -- jump to +101 priority when appropriate.\n"
245 " This application sets the following channel variable upon completion:\n"
246 " UPQMSTATUS The status of the attempt to unpause a queue \n"
247 " member as a text string, one of\n"
248 " UNPAUSED | NOTFOUND\n"
249 "Example: UnpauseQueueMember(|SIP/3000)\n";
251 static char *app_ql = "QueueLog" ;
252 static char *app_ql_synopsis = "Writes to the queue_log" ;
253 static char *app_ql_descrip =
254 " QueueLog(queuename|uniqueid|agent|event[|additionalinfo]):\n"
255 "Allows you to write your own events into the queue log\n"
256 "Example: QueueLog(101|${UNIQUEID}|${AGENT}|WENTONBREAK|600)\n";
258 /*! \brief Persistent Members astdb family */
259 static const char *pm_family = "Queue/PersistentMembers";
260 /* The maximum length of each persistent member queue database entry */
261 #define PM_MAX_LEN 8192
263 /*! \brief queues.conf [general] option */
264 static int queue_persistent_members = 0;
266 /*! \brief queues.conf per-queue weight option */
267 static int use_weight = 0;
269 /*! \brief queues.conf [general] option */
270 static int autofill_default = 0;
272 /*! \brief queues.conf [general] option */
273 static int montype_default = 0;
275 enum queue_result {
276 QUEUE_UNKNOWN = 0,
277 QUEUE_TIMEOUT = 1,
278 QUEUE_JOINEMPTY = 2,
279 QUEUE_LEAVEEMPTY = 3,
280 QUEUE_JOINUNAVAIL = 4,
281 QUEUE_LEAVEUNAVAIL = 5,
282 QUEUE_FULL = 6,
285 const struct {
286 enum queue_result id;
287 char *text;
288 } queue_results[] = {
289 { QUEUE_UNKNOWN, "UNKNOWN" },
290 { QUEUE_TIMEOUT, "TIMEOUT" },
291 { QUEUE_JOINEMPTY,"JOINEMPTY" },
292 { QUEUE_LEAVEEMPTY, "LEAVEEMPTY" },
293 { QUEUE_JOINUNAVAIL, "JOINUNAVAIL" },
294 { QUEUE_LEAVEUNAVAIL, "LEAVEUNAVAIL" },
295 { QUEUE_FULL, "FULL" },
298 /*! \brief We define a custom "local user" structure because we
299 use it not only for keeping track of what is in use but
300 also for keeping track of who we're dialing.
302 There are two "links" defined in this structure, q_next and call_next.
303 q_next links ALL defined callattempt structures into a linked list. call_next is
304 a link which allows for a subset of the callattempts to be traversed. This subset
305 is used in wait_for_answer so that irrelevant callattempts are not traversed. This
306 also is helpful so that queue logs are always accurate in the case where a call to
307 a member times out, especially if using the ringall strategy. */
309 struct callattempt {
310 struct callattempt *q_next;
311 struct callattempt *call_next;
312 struct ast_channel *chan;
313 char interface[256];
314 int stillgoing;
315 int metric;
316 int oldstatus;
317 time_t lastcall;
318 struct member *member;
322 struct queue_ent {
323 struct call_queue *parent; /*!< What queue is our parent */
324 char moh[80]; /*!< Name of musiconhold to be used */
325 char announce[80]; /*!< Announcement to play for member when call is answered */
326 char context[AST_MAX_CONTEXT]; /*!< Context when user exits queue */
327 char digits[AST_MAX_EXTENSION]; /*!< Digits entered while in queue */
328 int valid_digits; /*!< Digits entered correspond to valid extension. Exited */
329 int pos; /*!< Where we are in the queue */
330 int prio; /*!< Our priority */
331 int last_pos_said; /*!< Last position we told the user */
332 time_t last_periodic_announce_time; /*!< The last time we played a periodic announcement */
333 int last_periodic_announce_sound; /*!< The last periodic announcement we made */
334 time_t last_pos; /*!< Last time we told the user their position */
335 int opos; /*!< Where we started in the queue */
336 int handled; /*!< Whether our call was handled */
337 int pending; /*!< Non-zero if we are attempting to call a member */
338 int max_penalty; /*!< Limit the members that can take this call to this penalty or lower */
339 time_t start; /*!< When we started holding */
340 time_t expire; /*!< When this entry should expire (time out of queue) */
341 struct ast_channel *chan; /*!< Our channel */
342 struct queue_ent *next; /*!< The next queue entry */
345 struct member {
346 char interface[80]; /*!< Technology/Location */
347 char membername[80]; /*!< Member name to use in queue logs */
348 int penalty; /*!< Are we a last resort? */
349 int calls; /*!< Number of calls serviced by this member */
350 int dynamic; /*!< Are we dynamically added? */
351 int realtime; /*!< Is this member realtime? */
352 int status; /*!< Status of queue member */
353 int paused; /*!< Are we paused (not accepting calls)? */
354 time_t lastcall; /*!< When last successful call was hungup */
355 unsigned int dead:1; /*!< Used to detect members deleted in realtime */
356 unsigned int delme:1; /*!< Flag to delete entry on reload */
359 struct member_interface {
360 char interface[80];
361 AST_LIST_ENTRY(member_interface) list; /*!< Next call queue */
364 static AST_LIST_HEAD_STATIC(interfaces, member_interface);
366 /* values used in multi-bit flags in call_queue */
367 #define QUEUE_EMPTY_NORMAL 1
368 #define QUEUE_EMPTY_STRICT 2
369 #define ANNOUNCEHOLDTIME_ALWAYS 1
370 #define ANNOUNCEHOLDTIME_ONCE 2
371 #define QUEUE_EVENT_VARIABLES 3
373 struct call_queue {
374 ast_mutex_t lock;
375 char name[80]; /*!< Name */
376 char moh[80]; /*!< Music On Hold class to be used */
377 char announce[80]; /*!< Announcement to play when call is answered */
378 char context[AST_MAX_CONTEXT]; /*!< Exit context */
379 unsigned int monjoin:1;
380 unsigned int dead:1;
381 unsigned int joinempty:2;
382 unsigned int eventwhencalled:2;
383 unsigned int leavewhenempty:2;
384 unsigned int ringinuse:1;
385 unsigned int setinterfacevar:1;
386 unsigned int reportholdtime:1;
387 unsigned int wrapped:1;
388 unsigned int timeoutrestart:1;
389 unsigned int announceholdtime:2;
390 int strategy:4;
391 unsigned int maskmemberstatus:1;
392 unsigned int realtime:1;
393 unsigned int found:1;
394 int announcefrequency; /*!< How often to announce their position */
395 int periodicannouncefrequency; /*!< How often to play periodic announcement */
396 int roundingseconds; /*!< How many seconds do we round to? */
397 int holdtime; /*!< Current avg holdtime, based on an exponential average */
398 int callscompleted; /*!< Number of queue calls completed */
399 int callsabandoned; /*!< Number of queue calls abandoned */
400 int servicelevel; /*!< seconds setting for servicelevel*/
401 int callscompletedinsl; /*!< Number of calls answered with servicelevel*/
402 char monfmt[8]; /*!< Format to use when recording calls */
403 int montype; /*!< Monitor type Monitor vs. MixMonitor */
404 char sound_next[80]; /*!< Sound file: "Your call is now first in line" (def. queue-youarenext) */
405 char sound_thereare[80]; /*!< Sound file: "There are currently" (def. queue-thereare) */
406 char sound_calls[80]; /*!< Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting)*/
407 char sound_holdtime[80]; /*!< Sound file: "The current estimated total holdtime is" (def. queue-holdtime) */
408 char sound_minutes[80]; /*!< Sound file: "minutes." (def. queue-minutes) */
409 char sound_lessthan[80]; /*!< Sound file: "less-than" (def. queue-lessthan) */
410 char sound_seconds[80]; /*!< Sound file: "seconds." (def. queue-seconds) */
411 char sound_thanks[80]; /*!< Sound file: "Thank you for your patience." (def. queue-thankyou) */
412 char sound_reporthold[80]; /*!< Sound file: "Hold time" (def. queue-reporthold) */
413 char sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS][80];/*!< Sound files: Custom announce, no default */
415 int count; /*!< How many entries */
416 int maxlen; /*!< Max number of entries */
417 int wrapuptime; /*!< Wrapup Time */
419 int retry; /*!< Retry calling everyone after this amount of time */
420 int timeout; /*!< How long to wait for an answer */
421 int weight; /*!< Respective weight */
422 int autopause; /*!< Auto pause queue members if they fail to answer */
424 /* Queue strategy things */
425 int rrpos; /*!< Round Robin - position */
426 int memberdelay; /*!< Seconds to delay connecting member to caller */
427 int autofill; /*!< Ignore the head call status and ring an available agent */
429 struct ao2_container *members; /*!< Head of the list of members */
430 /*!
431 * \brief Number of members _logged in_
432 * \note There will be members in the members container that are not logged
433 * in, so this can not simply be replaced with ao2_container_count().
435 int membercount;
436 struct queue_ent *head; /*!< Head of the list of callers */
437 AST_LIST_ENTRY(call_queue) list; /*!< Next call queue */
440 static AST_LIST_HEAD_STATIC(queues, call_queue);
442 static int set_member_paused(const char *queuename, const char *interface, int paused);
444 static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
446 static void rr_dep_warning(void)
448 static unsigned int warned = 0;
450 if (!warned) {
451 ast_log(LOG_NOTICE, "The 'roundrobin' queue strategy is deprecated. Please use the 'rrmemory' strategy instead.\n");
452 warned = 1;
456 static void monjoin_dep_warning(void)
458 static unsigned int warned = 0;
459 if (!warned) {
460 ast_log(LOG_NOTICE, "The 'monitor-join' queue option is deprecated. Please use monitor-type=mixmonitor instead.\n");
461 warned = 1;
464 /*! \brief sets the QUEUESTATUS channel variable */
465 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
467 int i;
469 for (i = 0; i < sizeof(queue_results) / sizeof(queue_results[0]); i++) {
470 if (queue_results[i].id == res) {
471 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
472 return;
477 static char *int2strat(int strategy)
479 int x;
481 for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) {
482 if (strategy == strategies[x].strategy)
483 return strategies[x].name;
486 return "<unknown>";
489 static int strat2int(const char *strategy)
491 int x;
493 for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) {
494 if (!strcasecmp(strategy, strategies[x].name))
495 return strategies[x].strategy;
498 return -1;
501 /*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
502 static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
504 struct queue_ent *cur;
506 if (!q || !new)
507 return;
508 if (prev) {
509 cur = prev->next;
510 prev->next = new;
511 } else {
512 cur = q->head;
513 q->head = new;
515 new->next = cur;
516 new->parent = q;
517 new->pos = ++(*pos);
518 new->opos = *pos;
521 enum queue_member_status {
522 QUEUE_NO_MEMBERS,
523 QUEUE_NO_REACHABLE_MEMBERS,
524 QUEUE_NORMAL
527 /*! \brief Check if members are available
529 * This function checks to see if members are available to be called. If any member
530 * is available, the function immediately returns QUEUE_NORMAL. If no members are available,
531 * the appropriate reason why is returned
533 static enum queue_member_status get_member_status(struct call_queue *q, int max_penalty)
535 struct member *member;
536 struct ao2_iterator mem_iter;
537 enum queue_member_status result = QUEUE_NO_MEMBERS;
539 ast_mutex_lock(&q->lock);
540 mem_iter = ao2_iterator_init(q->members, 0);
541 while ((member = ao2_iterator_next(&mem_iter))) {
542 if (max_penalty && (member->penalty > max_penalty)) {
543 ao2_ref(member, -1);
544 continue;
547 if (member->paused) {
548 ao2_ref(member, -1);
549 continue;
552 switch (member->status) {
553 case AST_DEVICE_INVALID:
554 /* nothing to do */
555 ao2_ref(member, -1);
556 break;
557 case AST_DEVICE_UNAVAILABLE:
558 result = QUEUE_NO_REACHABLE_MEMBERS;
559 ao2_ref(member, -1);
560 break;
561 default:
562 ast_mutex_unlock(&q->lock);
563 ao2_ref(member, -1);
564 return QUEUE_NORMAL;
568 ast_mutex_unlock(&q->lock);
569 return result;
572 struct statechange {
573 AST_LIST_ENTRY(statechange) entry;
574 int state;
575 char dev[0];
578 static int update_status(const char *interface, const int status)
580 struct member *cur;
581 struct ao2_iterator mem_iter;
582 struct call_queue *q;
584 AST_LIST_LOCK(&queues);
585 AST_LIST_TRAVERSE(&queues, q, list) {
586 ast_mutex_lock(&q->lock);
587 mem_iter = ao2_iterator_init(q->members, 0);
588 while ((cur = ao2_iterator_next(&mem_iter))) {
589 char *tmp_interface;
590 char *slash_pos;
591 tmp_interface = ast_strdupa(cur->interface);
592 if ((slash_pos = strchr(tmp_interface, '/')))
593 if ((slash_pos = strchr(slash_pos + 1, '/')))
594 *slash_pos = '\0';
596 if (strcasecmp(interface, tmp_interface)) {
597 ao2_ref(cur, -1);
598 continue;
601 if (cur->status != status) {
602 cur->status = status;
603 if (q->maskmemberstatus) {
604 ao2_ref(cur, -1);
605 continue;
608 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
609 "Queue: %s\r\n"
610 "Location: %s\r\n"
611 "MemberName: %s\r\n"
612 "Membership: %s\r\n"
613 "Penalty: %d\r\n"
614 "CallsTaken: %d\r\n"
615 "LastCall: %d\r\n"
616 "Status: %d\r\n"
617 "Paused: %d\r\n",
618 q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : cur->realtime ? "realtime" : "static",
619 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
621 ao2_ref(cur, -1);
623 ast_mutex_unlock(&q->lock);
625 AST_LIST_UNLOCK(&queues);
627 return 0;
630 /*! \brief set a member's status based on device state of that member's interface*/
631 static void *handle_statechange(struct statechange *sc)
633 struct member_interface *curint;
634 char *loc;
635 char *technology;
637 technology = ast_strdupa(sc->dev);
638 loc = strchr(technology, '/');
639 if (loc) {
640 *loc++ = '\0';
641 } else {
642 return NULL;
645 AST_LIST_LOCK(&interfaces);
646 AST_LIST_TRAVERSE(&interfaces, curint, list) {
647 char *interface;
648 char *slash_pos;
649 interface = ast_strdupa(curint->interface);
650 if ((slash_pos = strchr(interface, '/')))
651 if ((slash_pos = strchr(slash_pos + 1, '/')))
652 *slash_pos = '\0';
654 if (!strcasecmp(interface, sc->dev))
655 break;
657 AST_LIST_UNLOCK(&interfaces);
659 if (!curint) {
660 if (option_debug > 2)
661 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n", technology, loc, sc->state, devstate2str(sc->state));
662 return NULL;
665 if (option_debug)
666 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state));
668 update_status(sc->dev, sc->state);
670 return NULL;
674 * \brief Data used by the device state thread
676 static struct {
677 /*! Set to 1 to stop the thread */
678 unsigned int stop:1;
679 /*! The device state monitoring thread */
680 pthread_t thread;
681 /*! Lock for the state change queue */
682 ast_mutex_t lock;
683 /*! Condition for the state change queue */
684 ast_cond_t cond;
685 /*! Queue of state changes */
686 AST_LIST_HEAD_NOLOCK(, statechange) state_change_q;
687 } device_state = {
688 .thread = AST_PTHREADT_NULL,
691 /*! \brief Consumer of the statechange queue */
692 static void *device_state_thread(void *data)
694 struct statechange *sc = NULL;
696 while (!device_state.stop) {
697 ast_mutex_lock(&device_state.lock);
698 if (!(sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry))) {
699 ast_cond_wait(&device_state.cond, &device_state.lock);
700 sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry);
702 ast_mutex_unlock(&device_state.lock);
704 /* Check to see if we were woken up to see the request to stop */
705 if (device_state.stop)
706 break;
708 if (!sc)
709 continue;
711 handle_statechange(sc);
713 free(sc);
714 sc = NULL;
717 if (sc)
718 free(sc);
720 while ((sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry)))
721 free(sc);
723 return NULL;
725 /*! \brief Producer of the statechange queue */
726 static int statechange_queue(const char *dev, int state, void *ign)
728 struct statechange *sc;
730 if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(dev) + 1)))
731 return 0;
733 sc->state = state;
734 strcpy(sc->dev, dev);
736 ast_mutex_lock(&device_state.lock);
737 AST_LIST_INSERT_TAIL(&device_state.state_change_q, sc, entry);
738 ast_cond_signal(&device_state.cond);
739 ast_mutex_unlock(&device_state.lock);
741 return 0;
743 /*! \brief allocate space for new queue member and set fields based on parameters passed */
744 static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused)
746 struct member *cur;
748 if ((cur = ao2_alloc(sizeof(*cur), NULL))) {
749 cur->penalty = penalty;
750 cur->paused = paused;
751 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
752 if (!ast_strlen_zero(membername))
753 ast_copy_string(cur->membername, membername, sizeof(cur->membername));
754 else
755 ast_copy_string(cur->membername, interface, sizeof(cur->membername));
756 if (!strchr(cur->interface, '/'))
757 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
758 cur->status = ast_device_state(interface);
761 return cur;
764 static struct call_queue *alloc_queue(const char *queuename)
766 struct call_queue *q;
768 if ((q = ast_calloc(1, sizeof(*q)))) {
769 ast_mutex_init(&q->lock);
770 ast_copy_string(q->name, queuename, sizeof(q->name));
772 return q;
775 static int compress_char(const char c)
777 if (c < 32)
778 return 0;
779 else if (c > 96)
780 return c - 64;
781 else
782 return c - 32;
785 static int member_hash_fn(const void *obj, const int flags)
787 const struct member *mem = obj;
788 const char *chname = strchr(mem->interface, '/');
789 int ret = 0, i;
790 if (!chname)
791 chname = mem->interface;
792 for (i = 0; i < 5 && chname[i]; i++)
793 ret += compress_char(chname[i]) << (i * 6);
794 return ret;
797 static int member_cmp_fn(void *obj1, void *obj2, int flags)
799 struct member *mem1 = obj1, *mem2 = obj2;
800 return strcmp(mem1->interface, mem2->interface) ? 0 : CMP_MATCH | CMP_STOP;
803 static void init_queue(struct call_queue *q)
805 int i;
807 q->dead = 0;
808 q->retry = DEFAULT_RETRY;
809 q->timeout = -1;
810 q->maxlen = 0;
811 q->announcefrequency = 0;
812 q->announceholdtime = 0;
813 q->roundingseconds = 0; /* Default - don't announce seconds */
814 q->servicelevel = 0;
815 q->ringinuse = 1;
816 q->setinterfacevar = 0;
817 q->autofill = autofill_default;
818 q->montype = montype_default;
819 q->moh[0] = '\0';
820 q->announce[0] = '\0';
821 q->context[0] = '\0';
822 q->monfmt[0] = '\0';
823 q->periodicannouncefrequency = 0;
824 q->reportholdtime = 0;
825 q->monjoin = 0;
826 q->wrapuptime = 0;
827 q->joinempty = 0;
828 q->leavewhenempty = 0;
829 q->memberdelay = 0;
830 q->maskmemberstatus = 0;
831 q->eventwhencalled = 0;
832 q->weight = 0;
833 q->timeoutrestart = 0;
834 if (!q->members)
835 q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
836 q->membercount = 0;
837 q->found = 1;
838 ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next));
839 ast_copy_string(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare));
840 ast_copy_string(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls));
841 ast_copy_string(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime));
842 ast_copy_string(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes));
843 ast_copy_string(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds));
844 ast_copy_string(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks));
845 ast_copy_string(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan));
846 ast_copy_string(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold));
847 ast_copy_string(q->sound_periodicannounce[0], "queue-periodic-announce", sizeof(q->sound_periodicannounce[0]));
848 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
849 q->sound_periodicannounce[i][0]='\0';
853 static void clear_queue(struct call_queue *q)
855 q->holdtime = 0;
856 q->callscompleted = 0;
857 q->callsabandoned = 0;
858 q->callscompletedinsl = 0;
859 q->wrapuptime = 0;
862 static int add_to_interfaces(const char *interface)
864 struct member_interface *curint;
866 AST_LIST_LOCK(&interfaces);
867 AST_LIST_TRAVERSE(&interfaces, curint, list) {
868 if (!strcasecmp(curint->interface, interface))
869 break;
872 if (curint) {
873 AST_LIST_UNLOCK(&interfaces);
874 return 0;
877 if (option_debug)
878 ast_log(LOG_DEBUG, "Adding %s to the list of interfaces that make up all of our queue members.\n", interface);
880 if ((curint = ast_calloc(1, sizeof(*curint)))) {
881 ast_copy_string(curint->interface, interface, sizeof(curint->interface));
882 AST_LIST_INSERT_HEAD(&interfaces, curint, list);
884 AST_LIST_UNLOCK(&interfaces);
886 return 0;
889 static int interface_exists_global(const char *interface)
891 struct call_queue *q;
892 struct member *mem, tmpmem;
893 int ret = 0;
895 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
897 AST_LIST_LOCK(&queues);
898 AST_LIST_TRAVERSE(&queues, q, list) {
899 ast_mutex_lock(&q->lock);
900 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
901 ao2_ref(mem, -1);
902 ret = 1;
904 ast_mutex_unlock(&q->lock);
905 if (ret)
906 break;
908 AST_LIST_UNLOCK(&queues);
910 return ret;
913 static int remove_from_interfaces(const char *interface)
915 struct member_interface *curint;
917 if (interface_exists_global(interface))
918 return 0;
920 AST_LIST_LOCK(&interfaces);
921 AST_LIST_TRAVERSE_SAFE_BEGIN(&interfaces, curint, list) {
922 if (!strcasecmp(curint->interface, interface)) {
923 if (option_debug)
924 ast_log(LOG_DEBUG, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface);
925 AST_LIST_REMOVE_CURRENT(&interfaces, list);
926 free(curint);
927 break;
930 AST_LIST_TRAVERSE_SAFE_END;
931 AST_LIST_UNLOCK(&interfaces);
933 return 0;
936 static void clear_and_free_interfaces(void)
938 struct member_interface *curint;
940 AST_LIST_LOCK(&interfaces);
941 while ((curint = AST_LIST_REMOVE_HEAD(&interfaces, list)))
942 free(curint);
943 AST_LIST_UNLOCK(&interfaces);
946 /*! \brief Configure a queue parameter.
947 \par
948 For error reporting, line number is passed for .conf static configuration.
949 For Realtime queues, linenum is -1.
950 The failunknown flag is set for config files (and static realtime) to show
951 errors for unknown parameters. It is cleared for dynamic realtime to allow
952 extra fields in the tables. */
953 static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
955 if (!strcasecmp(param, "musicclass") ||
956 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
957 ast_copy_string(q->moh, val, sizeof(q->moh));
958 } else if (!strcasecmp(param, "announce")) {
959 ast_copy_string(q->announce, val, sizeof(q->announce));
960 } else if (!strcasecmp(param, "context")) {
961 ast_copy_string(q->context, val, sizeof(q->context));
962 } else if (!strcasecmp(param, "timeout")) {
963 q->timeout = atoi(val);
964 if (q->timeout < 0)
965 q->timeout = DEFAULT_TIMEOUT;
966 } else if (!strcasecmp(param, "ringinuse")) {
967 q->ringinuse = ast_true(val);
968 } else if (!strcasecmp(param, "setinterfacevar")) {
969 q->setinterfacevar = ast_true(val);
970 } else if (!strcasecmp(param, "monitor-join")) {
971 monjoin_dep_warning();
972 q->monjoin = ast_true(val);
973 } else if (!strcasecmp(param, "monitor-format")) {
974 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
975 } else if (!strcasecmp(param, "queue-youarenext")) {
976 ast_copy_string(q->sound_next, val, sizeof(q->sound_next));
977 } else if (!strcasecmp(param, "queue-thereare")) {
978 ast_copy_string(q->sound_thereare, val, sizeof(q->sound_thereare));
979 } else if (!strcasecmp(param, "queue-callswaiting")) {
980 ast_copy_string(q->sound_calls, val, sizeof(q->sound_calls));
981 } else if (!strcasecmp(param, "queue-holdtime")) {
982 ast_copy_string(q->sound_holdtime, val, sizeof(q->sound_holdtime));
983 } else if (!strcasecmp(param, "queue-minutes")) {
984 ast_copy_string(q->sound_minutes, val, sizeof(q->sound_minutes));
985 } else if (!strcasecmp(param, "queue-seconds")) {
986 ast_copy_string(q->sound_seconds, val, sizeof(q->sound_seconds));
987 } else if (!strcasecmp(param, "queue-lessthan")) {
988 ast_copy_string(q->sound_lessthan, val, sizeof(q->sound_lessthan));
989 } else if (!strcasecmp(param, "queue-thankyou")) {
990 ast_copy_string(q->sound_thanks, val, sizeof(q->sound_thanks));
991 } else if (!strcasecmp(param, "queue-reporthold")) {
992 ast_copy_string(q->sound_reporthold, val, sizeof(q->sound_reporthold));
993 } else if (!strcasecmp(param, "announce-frequency")) {
994 q->announcefrequency = atoi(val);
995 } else if (!strcasecmp(param, "announce-round-seconds")) {
996 q->roundingseconds = atoi(val);
997 if (q->roundingseconds>60 || q->roundingseconds<0) {
998 if (linenum >= 0) {
999 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
1000 "using 0 instead for queue '%s' at line %d of queues.conf\n",
1001 val, param, q->name, linenum);
1002 } else {
1003 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
1004 "using 0 instead for queue '%s'\n", val, param, q->name);
1006 q->roundingseconds=0;
1008 } else if (!strcasecmp(param, "announce-holdtime")) {
1009 if (!strcasecmp(val, "once"))
1010 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
1011 else if (ast_true(val))
1012 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
1013 else
1014 q->announceholdtime = 0;
1015 } else if (!strcasecmp(param, "periodic-announce")) {
1016 if (strchr(val, '|')) {
1017 char *s, *buf = ast_strdupa(val);
1018 unsigned int i = 0;
1020 while ((s = strsep(&buf, "|"))) {
1021 ast_copy_string(q->sound_periodicannounce[i], s, sizeof(q->sound_periodicannounce[i]));
1022 i++;
1023 if (i == MAX_PERIODIC_ANNOUNCEMENTS)
1024 break;
1026 } else {
1027 ast_copy_string(q->sound_periodicannounce[0], val, sizeof(q->sound_periodicannounce[0]));
1029 } else if (!strcasecmp(param, "periodic-announce-frequency")) {
1030 q->periodicannouncefrequency = atoi(val);
1031 } else if (!strcasecmp(param, "retry")) {
1032 q->retry = atoi(val);
1033 if (q->retry <= 0)
1034 q->retry = DEFAULT_RETRY;
1035 } else if (!strcasecmp(param, "wrapuptime")) {
1036 q->wrapuptime = atoi(val);
1037 } else if (!strcasecmp(param, "autofill")) {
1038 q->autofill = ast_true(val);
1039 } else if (!strcasecmp(param, "monitor-type")) {
1040 if (!strcasecmp(val, "mixmonitor"))
1041 q->montype = 1;
1042 } else if (!strcasecmp(param, "autopause")) {
1043 q->autopause = ast_true(val);
1044 } else if (!strcasecmp(param, "maxlen")) {
1045 q->maxlen = atoi(val);
1046 if (q->maxlen < 0)
1047 q->maxlen = 0;
1048 } else if (!strcasecmp(param, "servicelevel")) {
1049 q->servicelevel= atoi(val);
1050 } else if (!strcasecmp(param, "strategy")) {
1051 q->strategy = strat2int(val);
1052 if (q->strategy < 0) {
1053 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
1054 val, q->name);
1055 q->strategy = QUEUE_STRATEGY_RINGALL;
1057 } else if (!strcasecmp(param, "joinempty")) {
1058 if (!strcasecmp(val, "strict"))
1059 q->joinempty = QUEUE_EMPTY_STRICT;
1060 else if (ast_true(val))
1061 q->joinempty = QUEUE_EMPTY_NORMAL;
1062 else
1063 q->joinempty = 0;
1064 } else if (!strcasecmp(param, "leavewhenempty")) {
1065 if (!strcasecmp(val, "strict"))
1066 q->leavewhenempty = QUEUE_EMPTY_STRICT;
1067 else if (ast_true(val))
1068 q->leavewhenempty = QUEUE_EMPTY_NORMAL;
1069 else
1070 q->leavewhenempty = 0;
1071 } else if (!strcasecmp(param, "eventmemberstatus")) {
1072 q->maskmemberstatus = !ast_true(val);
1073 } else if (!strcasecmp(param, "eventwhencalled")) {
1074 if (!strcasecmp(val, "vars")) {
1075 q->eventwhencalled = QUEUE_EVENT_VARIABLES;
1076 } else {
1077 q->eventwhencalled = ast_true(val) ? 1 : 0;
1079 } else if (!strcasecmp(param, "reportholdtime")) {
1080 q->reportholdtime = ast_true(val);
1081 } else if (!strcasecmp(param, "memberdelay")) {
1082 q->memberdelay = atoi(val);
1083 } else if (!strcasecmp(param, "weight")) {
1084 q->weight = atoi(val);
1085 if (q->weight)
1086 use_weight++;
1087 /* With Realtime queues, if the last queue using weights is deleted in realtime,
1088 we will not see any effect on use_weight until next reload. */
1089 } else if (!strcasecmp(param, "timeoutrestart")) {
1090 q->timeoutrestart = ast_true(val);
1091 } else if (failunknown) {
1092 if (linenum >= 0) {
1093 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
1094 q->name, param, linenum);
1095 } else {
1096 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
1101 static void rt_handle_member_record(struct call_queue *q, char *interface, const char *membername, const char *penalty_str, const char *paused_str)
1103 struct member *m, tmpmem;
1104 int penalty = 0;
1105 int paused = 0;
1107 if (penalty_str) {
1108 penalty = atoi(penalty_str);
1109 if (penalty < 0)
1110 penalty = 0;
1113 if (paused_str) {
1114 paused = atoi(paused_str);
1115 if (paused < 0)
1116 paused = 0;
1119 /* Find the member, or the place to put a new one. */
1120 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
1121 m = ao2_find(q->members, &tmpmem, OBJ_POINTER);
1123 /* Create a new one if not found, else update penalty */
1124 if (!m) {
1125 if ((m = create_queue_member(interface, membername, penalty, paused))) {
1126 m->dead = 0;
1127 m->realtime = 1;
1128 add_to_interfaces(interface);
1129 ao2_link(q->members, m);
1130 ao2_ref(m, -1);
1131 m = NULL;
1132 q->membercount++;
1134 } else {
1135 m->dead = 0; /* Do not delete this one. */
1136 if (paused_str)
1137 m->paused = paused;
1138 m->penalty = penalty;
1139 ao2_ref(m, -1);
1143 static void free_members(struct call_queue *q, int all)
1145 /* Free non-dynamic members */
1146 struct member *cur;
1147 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
1149 while ((cur = ao2_iterator_next(&mem_iter))) {
1150 if (all || !cur->dynamic) {
1151 ao2_unlink(q->members, cur);
1152 remove_from_interfaces(cur->interface);
1153 q->membercount--;
1155 ao2_ref(cur, -1);
1159 static void destroy_queue(struct call_queue *q)
1161 free_members(q, 1);
1162 ast_mutex_destroy(&q->lock);
1163 ao2_ref(q->members, -1);
1164 free(q);
1167 /*!\brief Reload a single queue via realtime.
1168 \return Return the queue, or NULL if it doesn't exist.
1169 \note Should be called with the global qlock locked. */
1170 static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
1172 struct ast_variable *v;
1173 struct call_queue *q;
1174 struct member *m;
1175 struct ao2_iterator mem_iter;
1176 char *interface = NULL;
1177 char *tmp, *tmp_name;
1178 char tmpbuf[64]; /* Must be longer than the longest queue param name. */
1180 /* Find the queue in the in-core list (we will create a new one if not found). */
1181 AST_LIST_TRAVERSE(&queues, q, list) {
1182 if (!strcasecmp(q->name, queuename))
1183 break;
1186 /* Static queues override realtime. */
1187 if (q) {
1188 ast_mutex_lock(&q->lock);
1189 if (!q->realtime) {
1190 if (q->dead) {
1191 ast_mutex_unlock(&q->lock);
1192 return NULL;
1193 } else {
1194 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
1195 ast_mutex_unlock(&q->lock);
1196 return q;
1199 } else if (!member_config)
1200 /* Not found in the list, and it's not realtime ... */
1201 return NULL;
1203 /* Check if queue is defined in realtime. */
1204 if (!queue_vars) {
1205 /* Delete queue from in-core list if it has been deleted in realtime. */
1206 if (q) {
1207 /*! \note Hmm, can't seem to distinguish a DB failure from a not
1208 found condition... So we might delete an in-core queue
1209 in case of DB failure. */
1210 ast_log(LOG_DEBUG, "Queue %s not found in realtime.\n", queuename);
1212 q->dead = 1;
1213 /* Delete if unused (else will be deleted when last caller leaves). */
1214 if (!q->count) {
1215 /* Delete. */
1216 AST_LIST_REMOVE(&queues, q, list);
1217 ast_mutex_unlock(&q->lock);
1218 destroy_queue(q);
1219 } else
1220 ast_mutex_unlock(&q->lock);
1222 return NULL;
1225 /* Create a new queue if an in-core entry does not exist yet. */
1226 if (!q) {
1227 if (!(q = alloc_queue(queuename)))
1228 return NULL;
1229 ast_mutex_lock(&q->lock);
1230 clear_queue(q);
1231 q->realtime = 1;
1232 AST_LIST_INSERT_HEAD(&queues, q, list);
1234 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
1236 memset(tmpbuf, 0, sizeof(tmpbuf));
1237 for (v = queue_vars; v; v = v->next) {
1238 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
1239 if ((tmp = strchr(v->name, '_'))) {
1240 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
1241 tmp_name = tmpbuf;
1242 tmp = tmp_name;
1243 while ((tmp = strchr(tmp, '_')))
1244 *tmp++ = '-';
1245 } else
1246 tmp_name = v->name;
1248 if (!ast_strlen_zero(v->value)) {
1249 /* Don't want to try to set the option if the value is empty */
1250 queue_set_param(q, tmp_name, v->value, -1, 0);
1254 if (q->strategy == QUEUE_STRATEGY_ROUNDROBIN)
1255 rr_dep_warning();
1257 /* Temporarily set realtime members dead so we can detect deleted ones.
1258 * Also set the membercount correctly for realtime*/
1259 mem_iter = ao2_iterator_init(q->members, 0);
1260 while ((m = ao2_iterator_next(&mem_iter))) {
1261 q->membercount++;
1262 if (m->realtime)
1263 m->dead = 1;
1264 ao2_ref(m, -1);
1267 while ((interface = ast_category_browse(member_config, interface))) {
1268 rt_handle_member_record(q, interface,
1269 ast_variable_retrieve(member_config, interface, "membername"),
1270 ast_variable_retrieve(member_config, interface, "penalty"),
1271 ast_variable_retrieve(member_config, interface, "paused"));
1274 /* Delete all realtime members that have been deleted in DB. */
1275 mem_iter = ao2_iterator_init(q->members, 0);
1276 while ((m = ao2_iterator_next(&mem_iter))) {
1277 if (m->dead) {
1278 ao2_unlink(q->members, m);
1279 ast_mutex_unlock(&q->lock);
1280 remove_from_interfaces(m->interface);
1281 ast_mutex_lock(&q->lock);
1282 q->membercount--;
1284 ao2_ref(m, -1);
1287 ast_mutex_unlock(&q->lock);
1289 return q;
1292 static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
1294 struct ast_variable *var;
1295 int ret = -1;
1297 if (!(var = ast_load_realtime("queue_members", "interface", mem->interface, "queue_name", queue_name, NULL)))
1298 return ret;
1299 while (var) {
1300 if (!strcmp(var->name, "uniqueid"))
1301 break;
1302 var = var->next;
1304 if (var && !ast_strlen_zero(var->value)) {
1305 if ((ast_update_realtime("queue_members", "uniqueid", var->value, field, value, NULL)) > -1)
1306 ret = 0;
1308 return ret;
1311 static void update_realtime_members(struct call_queue *q)
1313 struct ast_config *member_config = NULL;
1314 struct member *m;
1315 char *interface = NULL;
1316 struct ao2_iterator mem_iter;
1318 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , NULL))) {
1319 /*This queue doesn't have realtime members*/
1320 if (option_debug > 2)
1321 ast_log(LOG_DEBUG, "Queue %s has no realtime members defined. No need for update\n", q->name);
1322 return;
1325 ast_mutex_lock(&q->lock);
1327 /* Temporarily set realtime members dead so we can detect deleted ones.*/
1328 mem_iter = ao2_iterator_init(q->members, 0);
1329 while ((m = ao2_iterator_next(&mem_iter))) {
1330 if (m->realtime)
1331 m->dead = 1;
1332 ao2_ref(m, -1);
1335 while ((interface = ast_category_browse(member_config, interface))) {
1336 rt_handle_member_record(q, interface,
1337 S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
1338 ast_variable_retrieve(member_config, interface, "penalty"),
1339 ast_variable_retrieve(member_config, interface, "paused"));
1342 /* Delete all realtime members that have been deleted in DB. */
1343 mem_iter = ao2_iterator_init(q->members, 0);
1344 while ((m = ao2_iterator_next(&mem_iter))) {
1345 if (m->dead) {
1346 ao2_unlink(q->members, m);
1347 ast_mutex_unlock(&q->lock);
1348 remove_from_interfaces(m->interface);
1349 ast_mutex_lock(&q->lock);
1350 q->membercount--;
1352 ao2_ref(m, -1);
1354 ast_mutex_unlock(&q->lock);
1355 ast_config_destroy(member_config);
1358 static struct call_queue *load_realtime_queue(const char *queuename)
1360 struct ast_variable *queue_vars;
1361 struct ast_config *member_config = NULL;
1362 struct call_queue *q;
1364 /* Find the queue in the in-core list first. */
1365 AST_LIST_LOCK(&queues);
1366 AST_LIST_TRAVERSE(&queues, q, list) {
1367 if (!strcasecmp(q->name, queuename)) {
1368 break;
1371 AST_LIST_UNLOCK(&queues);
1373 if (!q || q->realtime) {
1374 /*! \note Load from realtime before taking the global qlock, to avoid blocking all
1375 queue operations while waiting for the DB.
1377 This will be two separate database transactions, so we might
1378 see queue parameters as they were before another process
1379 changed the queue and member list as it was after the change.
1380 Thus we might see an empty member list when a queue is
1381 deleted. In practise, this is unlikely to cause a problem. */
1383 queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
1384 if (queue_vars) {
1385 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
1386 if (!member_config) {
1387 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
1388 ast_variables_destroy(queue_vars);
1389 return NULL;
1393 AST_LIST_LOCK(&queues);
1395 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
1396 if (member_config)
1397 ast_config_destroy(member_config);
1398 if (queue_vars)
1399 ast_variables_destroy(queue_vars);
1401 AST_LIST_UNLOCK(&queues);
1402 } else {
1403 update_realtime_members(q);
1405 return q;
1408 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
1410 struct call_queue *q;
1411 struct queue_ent *cur, *prev = NULL;
1412 int res = -1;
1413 int pos = 0;
1414 int inserted = 0;
1415 enum queue_member_status stat;
1417 if (!(q = load_realtime_queue(queuename)))
1418 return res;
1420 AST_LIST_LOCK(&queues);
1421 ast_mutex_lock(&q->lock);
1423 /* This is our one */
1424 stat = get_member_status(q, qe->max_penalty);
1425 if (!q->joinempty && (stat == QUEUE_NO_MEMBERS))
1426 *reason = QUEUE_JOINEMPTY;
1427 else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_MEMBERS))
1428 *reason = QUEUE_JOINUNAVAIL;
1429 else if (q->maxlen && (q->count >= q->maxlen))
1430 *reason = QUEUE_FULL;
1431 else {
1432 /* There's space for us, put us at the right position inside
1433 * the queue.
1434 * Take into account the priority of the calling user */
1435 inserted = 0;
1436 prev = NULL;
1437 cur = q->head;
1438 while (cur) {
1439 /* We have higher priority than the current user, enter
1440 * before him, after all the other users with priority
1441 * higher or equal to our priority. */
1442 if ((!inserted) && (qe->prio > cur->prio)) {
1443 insert_entry(q, prev, qe, &pos);
1444 inserted = 1;
1446 cur->pos = ++pos;
1447 prev = cur;
1448 cur = cur->next;
1450 /* No luck, join at the end of the queue */
1451 if (!inserted)
1452 insert_entry(q, prev, qe, &pos);
1453 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
1454 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
1455 ast_copy_string(qe->context, q->context, sizeof(qe->context));
1456 q->count++;
1457 res = 0;
1458 manager_event(EVENT_FLAG_CALL, "Join",
1459 "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
1460 qe->chan->name,
1461 S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */
1462 S_OR(qe->chan->cid.cid_name, "unknown"),
1463 q->name, qe->pos, q->count, qe->chan->uniqueid );
1464 if (option_debug)
1465 ast_log(LOG_DEBUG, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
1467 ast_mutex_unlock(&q->lock);
1468 AST_LIST_UNLOCK(&queues);
1470 return res;
1473 static int play_file(struct ast_channel *chan, char *filename)
1475 int res;
1477 ast_stopstream(chan);
1479 res = ast_streamfile(chan, filename, chan->language);
1480 if (!res)
1481 res = ast_waitstream(chan, AST_DIGIT_ANY);
1483 ast_stopstream(chan);
1485 return res;
1488 static int valid_exit(struct queue_ent *qe, char digit)
1490 int digitlen = strlen(qe->digits);
1492 /* Prevent possible buffer overflow */
1493 if (digitlen < sizeof(qe->digits) - 2) {
1494 qe->digits[digitlen] = digit;
1495 qe->digits[digitlen + 1] = '\0';
1496 } else {
1497 qe->digits[0] = '\0';
1498 return 0;
1501 /* If there's no context to goto, short-circuit */
1502 if (ast_strlen_zero(qe->context))
1503 return 0;
1505 /* If the extension is bad, then reset the digits to blank */
1506 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) {
1507 qe->digits[0] = '\0';
1508 return 0;
1511 /* We have an exact match */
1512 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
1513 qe->valid_digits = 1;
1514 /* Return 1 on a successful goto */
1515 return 1;
1518 return 0;
1521 static int say_position(struct queue_ent *qe)
1523 int res = 0, avgholdmins, avgholdsecs;
1524 time_t now;
1526 /* Check to see if this is ludicrous -- if we just announced position, don't do it again*/
1527 time(&now);
1528 if ((now - qe->last_pos) < 15)
1529 return 0;
1531 /* If either our position has changed, or we are over the freq timer, say position */
1532 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency))
1533 return 0;
1535 ast_moh_stop(qe->chan);
1536 /* Say we're next, if we are */
1537 if (qe->pos == 1) {
1538 res = play_file(qe->chan, qe->parent->sound_next);
1539 if (res)
1540 goto playout;
1541 else
1542 goto posout;
1543 } else {
1544 res = play_file(qe->chan, qe->parent->sound_thereare);
1545 if (res)
1546 goto playout;
1547 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */
1548 if (res)
1549 goto playout;
1550 res = play_file(qe->chan, qe->parent->sound_calls);
1551 if (res)
1552 goto playout;
1554 /* Round hold time to nearest minute */
1555 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
1557 /* If they have specified a rounding then round the seconds as well */
1558 if (qe->parent->roundingseconds) {
1559 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
1560 avgholdsecs *= qe->parent->roundingseconds;
1561 } else {
1562 avgholdsecs = 0;
1565 if (option_verbose > 2)
1566 ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
1568 /* If the hold time is >1 min, if it's enabled, and if it's not
1569 supposed to be only once and we have already said it, say it */
1570 if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) &&
1571 (!(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE) && qe->last_pos)) {
1572 res = play_file(qe->chan, qe->parent->sound_holdtime);
1573 if (res)
1574 goto playout;
1576 if (avgholdmins > 0) {
1577 if (avgholdmins < 2) {
1578 res = play_file(qe->chan, qe->parent->sound_lessthan);
1579 if (res)
1580 goto playout;
1582 res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, NULL);
1583 if (res)
1584 goto playout;
1585 } else {
1586 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL);
1587 if (res)
1588 goto playout;
1591 res = play_file(qe->chan, qe->parent->sound_minutes);
1592 if (res)
1593 goto playout;
1595 if (avgholdsecs>0) {
1596 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL);
1597 if (res)
1598 goto playout;
1600 res = play_file(qe->chan, qe->parent->sound_seconds);
1601 if (res)
1602 goto playout;
1607 posout:
1608 if (option_verbose > 2)
1609 ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n",
1610 qe->chan->name, qe->parent->name, qe->pos);
1611 res = play_file(qe->chan, qe->parent->sound_thanks);
1613 playout:
1614 if ((res > 0 && !valid_exit(qe, res)) || res < 0)
1615 res = 0;
1617 /* Set our last_pos indicators */
1618 qe->last_pos = now;
1619 qe->last_pos_said = qe->pos;
1621 /* Don't restart music on hold if we're about to exit the caller from the queue */
1622 if (!res)
1623 ast_moh_start(qe->chan, qe->moh, NULL);
1625 return res;
1628 static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
1630 int oldvalue;
1632 /* Calculate holdtime using an exponential average */
1633 /* Thanks to SRT for this contribution */
1634 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
1636 ast_mutex_lock(&qe->parent->lock);
1637 oldvalue = qe->parent->holdtime;
1638 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
1639 ast_mutex_unlock(&qe->parent->lock);
1643 static void leave_queue(struct queue_ent *qe)
1645 struct call_queue *q;
1646 struct queue_ent *cur, *prev = NULL;
1647 int pos = 0;
1649 if (!(q = qe->parent))
1650 return;
1651 ast_mutex_lock(&q->lock);
1653 prev = NULL;
1654 for (cur = q->head; cur; cur = cur->next) {
1655 if (cur == qe) {
1656 q->count--;
1658 /* Take us out of the queue */
1659 manager_event(EVENT_FLAG_CALL, "Leave",
1660 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nUniqueid: %s\r\n",
1661 qe->chan->name, q->name, q->count, qe->chan->uniqueid);
1662 if (option_debug)
1663 ast_log(LOG_DEBUG, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
1664 /* Take us out of the queue */
1665 if (prev)
1666 prev->next = cur->next;
1667 else
1668 q->head = cur->next;
1669 } else {
1670 /* Renumber the people after us in the queue based on a new count */
1671 cur->pos = ++pos;
1672 prev = cur;
1675 ast_mutex_unlock(&q->lock);
1677 if (q->dead && !q->count) {
1678 /* It's dead and nobody is in it, so kill it */
1679 AST_LIST_LOCK(&queues);
1680 AST_LIST_REMOVE(&queues, q, list);
1681 AST_LIST_UNLOCK(&queues);
1682 destroy_queue(q);
1686 /* Hang up a list of outgoing calls */
1687 static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception)
1689 struct callattempt *oo;
1691 while (outgoing) {
1692 /* Hangup any existing lines we have open */
1693 if (outgoing->chan && (outgoing->chan != exception))
1694 ast_hangup(outgoing->chan);
1695 oo = outgoing;
1696 outgoing = outgoing->q_next;
1697 if (oo->member)
1698 ao2_ref(oo->member, -1);
1699 free(oo);
1704 /* traverse all defined queues which have calls waiting and contain this member
1705 return 0 if no other queue has precedence (higher weight) or 1 if found */
1706 static int compare_weight(struct call_queue *rq, struct member *member)
1708 struct call_queue *q;
1709 struct member *mem;
1710 int found = 0;
1712 /* &qlock and &rq->lock already set by try_calling()
1713 * to solve deadlock */
1714 AST_LIST_TRAVERSE(&queues, q, list) {
1715 if (q == rq) /* don't check myself, could deadlock */
1716 continue;
1717 ast_mutex_lock(&q->lock);
1718 if (q->count && q->members) {
1719 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
1720 ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
1721 if (q->weight > rq->weight) {
1722 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);
1723 found = 1;
1725 ao2_ref(mem, -1);
1728 ast_mutex_unlock(&q->lock);
1729 if (found)
1730 break;
1732 return found;
1735 /*! \brief common hangup actions */
1736 static void do_hang(struct callattempt *o)
1738 o->stillgoing = 0;
1739 ast_hangup(o->chan);
1740 o->chan = NULL;
1743 static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
1745 char *tmp = alloca(len);
1747 if (pbx_builtin_serialize_variables(chan, tmp, len)) {
1748 int i, j;
1750 /* convert "\n" to "\nVariable: " */
1751 strcpy(vars, "Variable: ");
1753 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) {
1754 vars[j] = tmp[i];
1756 if (tmp[i + 1] == '\0')
1757 break;
1758 if (tmp[i] == '\n') {
1759 vars[j++] = '\r';
1760 vars[j++] = '\n';
1762 ast_copy_string(&(vars[j]), "Variable: ", len - j);
1763 j += 9;
1766 if (j > len - 3)
1767 j = len - 3;
1768 vars[j++] = '\r';
1769 vars[j++] = '\n';
1770 vars[j] = '\0';
1771 } else {
1772 /* there are no channel variables; leave it blank */
1773 *vars = '\0';
1775 return vars;
1778 /*! \brief Part 2 of ring_one
1780 * Does error checking before attempting to request a channel and call a member. This
1781 * function is only called from ring_one
1783 static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
1785 int res;
1786 int status;
1787 char tech[256];
1788 char *location;
1789 const char *macrocontext, *macroexten;
1791 /* on entry here, we know that tmp->chan == NULL */
1792 if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
1793 if (option_debug)
1794 ast_log(LOG_DEBUG, "Wrapuptime not yet expired for %s\n", tmp->interface);
1795 if (qe->chan->cdr)
1796 ast_cdr_busy(qe->chan->cdr);
1797 tmp->stillgoing = 0;
1798 (*busies)++;
1799 return 0;
1802 if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
1803 if (option_debug)
1804 ast_log(LOG_DEBUG, "%s in use, can't receive call\n", tmp->interface);
1805 if (qe->chan->cdr)
1806 ast_cdr_busy(qe->chan->cdr);
1807 tmp->stillgoing = 0;
1808 return 0;
1811 if (tmp->member->paused) {
1812 if (option_debug)
1813 ast_log(LOG_DEBUG, "%s paused, can't receive call\n", tmp->interface);
1814 if (qe->chan->cdr)
1815 ast_cdr_busy(qe->chan->cdr);
1816 tmp->stillgoing = 0;
1817 return 0;
1819 if (use_weight && compare_weight(qe->parent,tmp->member)) {
1820 ast_log(LOG_DEBUG, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
1821 if (qe->chan->cdr)
1822 ast_cdr_busy(qe->chan->cdr);
1823 tmp->stillgoing = 0;
1824 (*busies)++;
1825 return 0;
1828 ast_copy_string(tech, tmp->interface, sizeof(tech));
1829 if ((location = strchr(tech, '/')))
1830 *location++ = '\0';
1831 else
1832 location = "";
1834 /* Request the peer */
1835 tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
1836 if (!tmp->chan) { /* If we can't, just go on to the next call */
1837 if (qe->chan->cdr)
1838 ast_cdr_busy(qe->chan->cdr);
1839 tmp->stillgoing = 0;
1841 update_status(tmp->member->interface, ast_device_state(tmp->member->interface));
1843 ast_mutex_lock(&qe->parent->lock);
1844 qe->parent->rrpos++;
1845 ast_mutex_unlock(&qe->parent->lock);
1847 (*busies)++;
1848 return 0;
1851 tmp->chan->appl = "AppQueue";
1852 tmp->chan->data = "(Outgoing Line)";
1853 tmp->chan->whentohangup = 0;
1854 if (tmp->chan->cid.cid_num)
1855 free(tmp->chan->cid.cid_num);
1856 tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num);
1857 if (tmp->chan->cid.cid_name)
1858 free(tmp->chan->cid.cid_name);
1859 tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name);
1860 if (tmp->chan->cid.cid_ani)
1861 free(tmp->chan->cid.cid_ani);
1862 tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani);
1864 /* Inherit specially named variables from parent channel */
1865 ast_channel_inherit_variables(qe->chan, tmp->chan);
1867 /* Presense of ADSI CPE on outgoing channel follows ours */
1868 tmp->chan->adsicpe = qe->chan->adsicpe;
1870 /* Inherit context and extension */
1871 ast_channel_lock(qe->chan);
1872 macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT");
1873 if (!ast_strlen_zero(macrocontext))
1874 ast_copy_string(tmp->chan->dialcontext, macrocontext, sizeof(tmp->chan->dialcontext));
1875 else
1876 ast_copy_string(tmp->chan->dialcontext, qe->chan->context, sizeof(tmp->chan->dialcontext));
1877 macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN");
1878 if (!ast_strlen_zero(macroexten))
1879 ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten));
1880 else
1881 ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten));
1882 ast_channel_unlock(qe->chan);
1884 /* Place the call, but don't wait on the answer */
1885 if ((res = ast_call(tmp->chan, location, 0))) {
1886 /* Again, keep going even if there's an error */
1887 if (option_debug)
1888 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
1889 if (option_verbose > 2)
1890 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface);
1891 do_hang(tmp);
1892 (*busies)++;
1893 update_status(tmp->member->interface, ast_device_state(tmp->member->interface));
1894 return 0;
1895 } else if (qe->parent->eventwhencalled) {
1896 char vars[2048];
1898 manager_event(EVENT_FLAG_AGENT, "AgentCalled",
1899 "AgentCalled: %s\r\n"
1900 "AgentName: %s\r\n"
1901 "ChannelCalling: %s\r\n"
1902 "CallerID: %s\r\n"
1903 "CallerIDName: %s\r\n"
1904 "Context: %s\r\n"
1905 "Extension: %s\r\n"
1906 "Priority: %d\r\n"
1907 "%s",
1908 tmp->interface, tmp->member->membername, qe->chan->name,
1909 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
1910 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
1911 qe->chan->context, qe->chan->exten, qe->chan->priority,
1912 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
1913 if (option_verbose > 2)
1914 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface);
1917 update_status(tmp->member->interface, ast_device_state(tmp->member->interface));
1918 return 1;
1921 /*! \brief find the entry with the best metric, or NULL */
1922 static struct callattempt *find_best(struct callattempt *outgoing)
1924 struct callattempt *best = NULL, *cur;
1926 for (cur = outgoing; cur; cur = cur->q_next) {
1927 if (cur->stillgoing && /* Not already done */
1928 !cur->chan && /* Isn't already going */
1929 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */
1930 best = cur;
1934 return best;
1937 /*! \brief Place a call to a queue member
1939 * Once metrics have been calculated for each member, this function is used
1940 * to place a call to the appropriate member (or members). The low-level
1941 * channel-handling and error detection is handled in ring_entry
1943 * Returns 1 if a member was called successfully, 0 otherwise
1945 static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
1947 int ret = 0;
1949 while (ret == 0) {
1950 struct callattempt *best = find_best(outgoing);
1951 if (!best) {
1952 if (option_debug)
1953 ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n");
1954 break;
1956 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
1957 struct callattempt *cur;
1958 /* Ring everyone who shares this best metric (for ringall) */
1959 for (cur = outgoing; cur; cur = cur->q_next) {
1960 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
1961 if (option_debug)
1962 ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
1963 ret |= ring_entry(qe, cur, busies);
1966 } else {
1967 /* Ring just the best channel */
1968 if (option_debug)
1969 ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric);
1970 ret = ring_entry(qe, best, busies);
1974 return ret;
1977 static int store_next(struct queue_ent *qe, struct callattempt *outgoing)
1979 struct callattempt *best = find_best(outgoing);
1981 if (best) {
1982 /* Ring just the best channel */
1983 if (option_debug)
1984 ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric);
1985 qe->parent->rrpos = best->metric % 1000;
1986 } else {
1987 /* Just increment rrpos */
1988 if (qe->parent->wrapped) {
1989 /* No more channels, start over */
1990 qe->parent->rrpos = 0;
1991 } else {
1992 /* Prioritize next entry */
1993 qe->parent->rrpos++;
1996 qe->parent->wrapped = 0;
1998 return 0;
2001 static int say_periodic_announcement(struct queue_ent *qe)
2003 int res = 0;
2004 time_t now;
2006 /* Get the current time */
2007 time(&now);
2009 /* Check to see if it is time to announce */
2010 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
2011 return 0;
2013 /* Stop the music on hold so we can play our own file */
2014 ast_moh_stop(qe->chan);
2016 if (option_verbose > 2)
2017 ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n");
2019 /* Check to make sure we have a sound file. If not, reset to the first sound file */
2020 if (qe->last_periodic_announce_sound >= MAX_PERIODIC_ANNOUNCEMENTS || !strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound])) {
2021 qe->last_periodic_announce_sound = 0;
2024 /* play the announcement */
2025 res = play_file(qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]);
2027 if ((res > 0 && !valid_exit(qe, res)) || res < 0)
2028 res = 0;
2030 /* Resume Music on Hold if the caller is going to stay in the queue */
2031 if (!res)
2032 ast_moh_start(qe->chan, qe->moh, NULL);
2034 /* update last_periodic_announce_time */
2035 qe->last_periodic_announce_time = now;
2037 /* Update the current periodic announcement to the next announcement */
2038 qe->last_periodic_announce_sound++;
2040 return res;
2043 static void record_abandoned(struct queue_ent *qe)
2045 ast_mutex_lock(&qe->parent->lock);
2046 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
2047 "Queue: %s\r\n"
2048 "Uniqueid: %s\r\n"
2049 "Position: %d\r\n"
2050 "OriginalPosition: %d\r\n"
2051 "HoldTime: %d\r\n",
2052 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start));
2054 qe->parent->callsabandoned++;
2055 ast_mutex_unlock(&qe->parent->lock);
2058 /*! \brief RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. */
2059 static void rna(int rnatime, struct queue_ent *qe, char *interface, char *membername)
2061 if (option_verbose > 2)
2062 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", rnatime);
2063 ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
2064 if (qe->parent->autopause) {
2065 if (!set_member_paused(qe->parent->name, interface, 1)) {
2066 if (option_verbose > 2)
2067 ast_verbose( VERBOSE_PREFIX_3 "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name);
2068 } else {
2069 if (option_verbose > 2)
2070 ast_verbose( VERBOSE_PREFIX_3 "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
2073 return;
2076 #define AST_MAX_WATCHERS 256
2077 /*! \brief Wait for a member to answer the call
2079 * \param[in] qe the queue_ent corresponding to the caller in the queue
2080 * \param[in] outgoing the list of callattempts. Relevant ones will have their chan and stillgoing parameters non-zero
2081 * \param[in] to the amount of time (in milliseconds) to wait for a response
2082 * \param[out] digit if a user presses a digit to exit the queue, this is the digit the caller pressed
2083 * \param[in] prebusies number of busy members calculated prior to calling wait_for_answer
2084 * \param[in] caller_disconnect if the 'H' option is used when calling Queue(), this is used to detect if the caller pressed * to disconnect the call
2085 * \param[in] forwardsallowed used to detect if we should allow call forwarding, based on the 'i' option to Queue()
2087 static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
2089 char *queue = qe->parent->name;
2090 struct callattempt *o, *start = NULL, *prev = NULL;
2091 int status;
2092 int numbusies = prebusies;
2093 int numnochan = 0;
2094 int stillgoing = 0;
2095 int orig = *to;
2096 struct ast_frame *f;
2097 struct callattempt *peer = NULL;
2098 struct ast_channel *winner;
2099 struct ast_channel *in = qe->chan;
2100 char on[80] = "";
2101 char membername[80] = "";
2102 long starttime = 0;
2103 long endtime = 0;
2105 starttime = (long) time(NULL);
2107 while (*to && !peer) {
2108 int numlines, retry, pos = 1;
2109 struct ast_channel *watchers[AST_MAX_WATCHERS];
2110 watchers[0] = in;
2111 start = NULL;
2113 for (retry = 0; retry < 2; retry++) {
2114 numlines = 0;
2115 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
2116 if (o->stillgoing) { /* Keep track of important channels */
2117 stillgoing = 1;
2118 if (o->chan) {
2119 watchers[pos++] = o->chan;
2120 if (!start)
2121 start = o;
2122 else
2123 prev->call_next = o;
2124 prev = o;
2127 numlines++;
2129 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
2130 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */)
2131 break;
2132 /* On "ringall" strategy we only move to the next penalty level
2133 when *all* ringing phones are done in the current penalty level */
2134 ring_one(qe, outgoing, &numbusies);
2135 /* and retry... */
2137 if (pos == 1 /* not found */) {
2138 if (numlines == (numbusies + numnochan)) {
2139 ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
2140 } else {
2141 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan);
2143 *to = 0;
2144 return NULL;
2146 winner = ast_waitfor_n(watchers, pos, to);
2147 for (o = start; o; o = o->call_next) {
2148 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
2149 if (!peer) {
2150 if (option_verbose > 2)
2151 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
2152 peer = o;
2154 } else if (o->chan && (o->chan == winner)) {
2156 ast_copy_string(on, o->member->interface, sizeof(on));
2157 ast_copy_string(membername, o->member->membername, sizeof(membername));
2159 if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) {
2160 if (option_verbose > 2)
2161 ast_verbose(VERBOSE_PREFIX_3 "Forwarding %s to '%s' prevented.\n", in->name, o->chan->call_forward);
2162 numnochan++;
2163 do_hang(o);
2164 winner = NULL;
2165 continue;
2166 } else if (!ast_strlen_zero(o->chan->call_forward)) {
2167 char tmpchan[256];
2168 char *stuff;
2169 char *tech;
2171 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
2172 if ((stuff = strchr(tmpchan, '/'))) {
2173 *stuff++ = '\0';
2174 tech = tmpchan;
2175 } else {
2176 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
2177 stuff = tmpchan;
2178 tech = "Local";
2180 /* Before processing channel, go ahead and check for forwarding */
2181 if (option_verbose > 2)
2182 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
2183 /* Setup parameters */
2184 o->chan = ast_request(tech, in->nativeformats, stuff, &status);
2185 if (!o->chan) {
2186 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
2187 o->stillgoing = 0;
2188 numnochan++;
2189 } else {
2190 ast_channel_inherit_variables(in, o->chan);
2191 ast_channel_datastore_inherit(in, o->chan);
2192 if (o->chan->cid.cid_num)
2193 free(o->chan->cid.cid_num);
2194 o->chan->cid.cid_num = ast_strdup(in->cid.cid_num);
2196 if (o->chan->cid.cid_name)
2197 free(o->chan->cid.cid_name);
2198 o->chan->cid.cid_name = ast_strdup(in->cid.cid_name);
2200 ast_string_field_set(o->chan, accountcode, in->accountcode);
2201 o->chan->cdrflags = in->cdrflags;
2203 if (in->cid.cid_ani) {
2204 if (o->chan->cid.cid_ani)
2205 free(o->chan->cid.cid_ani);
2206 o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani);
2208 if (o->chan->cid.cid_rdnis)
2209 free(o->chan->cid.cid_rdnis);
2210 o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten));
2211 if (ast_call(o->chan, tmpchan, 0)) {
2212 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
2213 do_hang(o);
2214 numnochan++;
2217 /* Hangup the original channel now, in case we needed it */
2218 ast_hangup(winner);
2219 continue;
2221 f = ast_read(winner);
2222 if (f) {
2223 if (f->frametype == AST_FRAME_CONTROL) {
2224 switch (f->subclass) {
2225 case AST_CONTROL_ANSWER:
2226 /* This is our guy if someone answered. */
2227 if (!peer) {
2228 if (option_verbose > 2)
2229 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
2230 peer = o;
2232 break;
2233 case AST_CONTROL_BUSY:
2234 if (option_verbose > 2)
2235 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
2236 if (in->cdr)
2237 ast_cdr_busy(in->cdr);
2238 do_hang(o);
2239 endtime = (long)time(NULL);
2240 endtime -= starttime;
2241 rna(endtime*1000, qe, on, membername);
2242 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2243 if (qe->parent->timeoutrestart)
2244 *to = orig;
2245 ring_one(qe, outgoing, &numbusies);
2247 numbusies++;
2248 break;
2249 case AST_CONTROL_CONGESTION:
2250 if (option_verbose > 2)
2251 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
2252 if (in->cdr)
2253 ast_cdr_busy(in->cdr);
2254 endtime = (long)time(NULL);
2255 endtime -= starttime;
2256 rna(endtime*1000, qe, on, membername);
2257 do_hang(o);
2258 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2259 if (qe->parent->timeoutrestart)
2260 *to = orig;
2261 ring_one(qe, outgoing, &numbusies);
2263 numbusies++;
2264 break;
2265 case AST_CONTROL_RINGING:
2266 if (option_verbose > 2)
2267 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
2268 break;
2269 case AST_CONTROL_OFFHOOK:
2270 /* Ignore going off hook */
2271 break;
2272 default:
2273 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
2276 ast_frfree(f);
2277 } else {
2278 endtime = (long) time(NULL) - starttime;
2279 rna(endtime * 1000, qe, on, membername);
2280 do_hang(o);
2281 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2282 if (qe->parent->timeoutrestart)
2283 *to = orig;
2284 ring_one(qe, outgoing, &numbusies);
2289 if (winner == in) {
2290 f = ast_read(in);
2291 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
2292 /* Got hung up */
2293 *to = -1;
2294 if (f)
2295 ast_frfree(f);
2296 return NULL;
2298 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) {
2299 if (option_verbose > 3)
2300 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
2301 *to = 0;
2302 ast_frfree(f);
2303 return NULL;
2305 if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass)) {
2306 if (option_verbose > 3)
2307 ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass);
2308 *to = 0;
2309 *digit = f->subclass;
2310 ast_frfree(f);
2311 return NULL;
2313 ast_frfree(f);
2315 if (!*to) {
2316 for (o = start; o; o = o->call_next)
2317 rna(orig, qe, o->interface, o->member->membername);
2321 return peer;
2323 /*! \brief Check if we should start attempting to call queue members
2325 * The behavior of this function is dependent first on whether autofill is enabled
2326 * and second on whether the ring strategy is ringall. If autofill is not enabled,
2327 * then return true if we're the head of the queue. If autofill is enabled, then
2328 * we count the available members and see if the number of available members is enough
2329 * that given our position in the queue, we would theoretically be able to connect to
2330 * one of those available members
2332 static int is_our_turn(struct queue_ent *qe)
2334 struct queue_ent *ch;
2335 struct member *cur;
2336 int avl = 0;
2337 int idx = 0;
2338 int res;
2340 if (!qe->parent->autofill) {
2341 /* Atomically read the parent head -- does not need a lock */
2342 ch = qe->parent->head;
2343 /* If we are now at the top of the head, break out */
2344 if (ch == qe) {
2345 if (option_debug)
2346 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
2347 res = 1;
2348 } else {
2349 if (option_debug)
2350 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
2351 res = 0;
2354 } else {
2355 /* This needs a lock. How many members are available to be served? */
2356 ast_mutex_lock(&qe->parent->lock);
2358 ch = qe->parent->head;
2360 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
2361 if (option_debug)
2362 ast_log(LOG_DEBUG, "Even though there may be multiple members available, the strategy is ringall so only the head call is allowed in\n");
2363 avl = 1;
2364 } else {
2365 struct ao2_iterator mem_iter = ao2_iterator_init(qe->parent->members, 0);
2366 while ((cur = ao2_iterator_next(&mem_iter))) {
2367 switch (cur->status) {
2368 case AST_DEVICE_INUSE:
2369 if (!qe->parent->ringinuse)
2370 break;
2371 /* else fall through */
2372 case AST_DEVICE_NOT_INUSE:
2373 case AST_DEVICE_UNKNOWN:
2374 if (!cur->paused)
2375 avl++;
2376 break;
2378 ao2_ref(cur, -1);
2382 if (option_debug)
2383 ast_log(LOG_DEBUG, "There are %d available members.\n", avl);
2385 while ((idx < avl) && (ch) && (ch != qe)) {
2386 if (!ch->pending)
2387 idx++;
2388 ch = ch->next;
2391 /* If the queue entry is within avl [the number of available members] calls from the top ... */
2392 if (ch && idx < avl) {
2393 if (option_debug)
2394 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
2395 res = 1;
2396 } else {
2397 if (option_debug)
2398 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
2399 res = 0;
2402 ast_mutex_unlock(&qe->parent->lock);
2405 return res;
2407 /*! \brief The waiting areas for callers who are not actively calling members
2409 * This function is one large loop. This function will return if a caller
2410 * either exits the queue or it becomes that caller's turn to attempt calling
2411 * queue members. Inside the loop, we service the caller with periodic announcements,
2412 * holdtime announcements, etc. as configured in queues.conf
2414 * \retval 0 if the caller's turn has arrived
2415 * \retval -1 if the caller should exit the queue.
2417 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
2419 int res = 0;
2421 /* This is the holding pen for callers 2 through maxlen */
2422 for (;;) {
2423 enum queue_member_status stat;
2425 if (is_our_turn(qe))
2426 break;
2428 /* If we have timed out, break out */
2429 if (qe->expire && (time(NULL) >= qe->expire)) {
2430 *reason = QUEUE_TIMEOUT;
2431 break;
2434 stat = get_member_status(qe->parent, qe->max_penalty);
2436 /* leave the queue if no agents, if enabled */
2437 if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
2438 *reason = QUEUE_LEAVEEMPTY;
2439 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
2440 leave_queue(qe);
2441 break;
2444 /* leave the queue if no reachable agents, if enabled */
2445 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
2446 *reason = QUEUE_LEAVEUNAVAIL;
2447 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
2448 leave_queue(qe);
2449 break;
2452 /* Make a position announcement, if enabled */
2453 if (qe->parent->announcefrequency && !ringing &&
2454 (res = say_position(qe)))
2455 break;
2457 /* If we have timed out, break out */
2458 if (qe->expire && (time(NULL) >= qe->expire)) {
2459 *reason = QUEUE_TIMEOUT;
2460 break;
2463 /* Make a periodic announcement, if enabled */
2464 if (qe->parent->periodicannouncefrequency && !ringing &&
2465 (res = say_periodic_announcement(qe)))
2466 break;
2468 /* If we have timed out, break out */
2469 if (qe->expire && (time(NULL) >= qe->expire)) {
2470 *reason = QUEUE_TIMEOUT;
2471 break;
2474 /* Wait a second before checking again */
2475 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
2476 if (res > 0 && !valid_exit(qe, res))
2477 res = 0;
2478 else
2479 break;
2482 /* If we have timed out, break out */
2483 if (qe->expire && (time(NULL) >= qe->expire)) {
2484 *reason = QUEUE_TIMEOUT;
2485 break;
2489 return res;
2492 static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl)
2494 ast_mutex_lock(&q->lock);
2495 time(&member->lastcall);
2496 member->calls++;
2497 q->callscompleted++;
2498 if (callcompletedinsl)
2499 q->callscompletedinsl++;
2500 ast_mutex_unlock(&q->lock);
2501 return 0;
2504 /*! \brief Calculate the metric of each member in the outgoing callattempts
2506 * A numeric metric is given to each member depending on the ring strategy used
2507 * by the queue. Members with lower metrics will be called before members with
2508 * higher metrics
2510 static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
2512 if (qe->max_penalty && (mem->penalty > qe->max_penalty))
2513 return -1;
2515 switch (q->strategy) {
2516 case QUEUE_STRATEGY_RINGALL:
2517 /* Everyone equal, except for penalty */
2518 tmp->metric = mem->penalty * 1000000;
2519 break;
2520 case QUEUE_STRATEGY_ROUNDROBIN:
2521 if (!pos) {
2522 if (!q->wrapped) {
2523 /* No more channels, start over */
2524 q->rrpos = 0;
2525 } else {
2526 /* Prioritize next entry */
2527 q->rrpos++;
2529 q->wrapped = 0;
2531 /* Fall through */
2532 case QUEUE_STRATEGY_RRMEMORY:
2533 if (pos < q->rrpos) {
2534 tmp->metric = 1000 + pos;
2535 } else {
2536 if (pos > q->rrpos)
2537 /* Indicate there is another priority */
2538 q->wrapped = 1;
2539 tmp->metric = pos;
2541 tmp->metric += mem->penalty * 1000000;
2542 break;
2543 case QUEUE_STRATEGY_RANDOM:
2544 tmp->metric = ast_random() % 1000;
2545 tmp->metric += mem->penalty * 1000000;
2546 break;
2547 case QUEUE_STRATEGY_FEWESTCALLS:
2548 tmp->metric = mem->calls;
2549 tmp->metric += mem->penalty * 1000000;
2550 break;
2551 case QUEUE_STRATEGY_LEASTRECENT:
2552 if (!mem->lastcall)
2553 tmp->metric = 0;
2554 else
2555 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
2556 tmp->metric += mem->penalty * 1000000;
2557 break;
2558 default:
2559 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
2560 break;
2562 return 0;
2565 struct queue_transfer_ds {
2566 struct queue_ent *qe;
2567 struct member *member;
2568 int starttime;
2571 static void queue_transfer_destroy(void *data)
2573 struct queue_transfer_ds *qtds = data;
2574 ast_free(qtds);
2577 /*! \brief a datastore used to help correctly log attended transfers of queue callers
2579 static const struct ast_datastore_info queue_transfer_info = {
2580 .type = "queue_transfer",
2581 .chan_fixup = queue_transfer_fixup,
2582 .destroy = queue_transfer_destroy,
2585 /*! \brief Log an attended transfer when a queue caller channel is masqueraded
2587 * When a caller is masqueraded, we want to log a transfer. Fixup time is the closest we can come to when
2588 * the actual transfer occurs. This happens during the masquerade after datastores are moved from old_chan
2589 * to new_chan. This is why new_chan is referenced for exten, context, and datastore information.
2591 * At the end of this, we want to remove the datastore so that this fixup function is not called on any
2592 * future masquerades of the caller during the current call.
2594 static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
2596 struct queue_transfer_ds *qtds = data;
2597 struct queue_ent *qe = qtds->qe;
2598 struct member *member = qtds->member;
2599 int callstart = qtds->starttime;
2600 struct ast_datastore *datastore;
2602 ast_queue_log(qe->parent->name, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld",
2603 new_chan->exten, new_chan->context, (long) (callstart - qe->start),
2604 (long) (time(NULL) - callstart));
2606 if (!(datastore = ast_channel_datastore_find(new_chan, &queue_transfer_info, NULL))) {
2607 ast_log(LOG_WARNING, "Can't find the queue_transfer datastore.\n");
2608 return;
2611 ast_channel_datastore_remove(new_chan, datastore);
2612 ast_channel_datastore_free(datastore);
2615 /*! \brief mechanism to tell if a queue caller was atxferred by a queue member.
2617 * When a caller is atxferred, then the queue_transfer_info datastore
2618 * is removed from the channel. If it's still there after the bridge is
2619 * broken, then the caller was not atxferred.
2621 static int attended_transfer_occurred(struct ast_channel *chan)
2623 return ast_channel_datastore_find(chan, &queue_transfer_info, NULL) ? 0 : 1;
2626 /*! \brief create a datastore for storing relevant info to log attended transfers in the queue_log
2628 static void setup_transfer_datastore(struct queue_ent *qe, struct member *member, int starttime)
2630 struct ast_datastore *ds;
2631 struct queue_transfer_ds *qtds = ast_calloc(1, sizeof(*qtds));
2633 if (!qtds) {
2634 ast_log(LOG_WARNING, "Memory allocation error!\n");
2635 return;
2638 ast_channel_lock(qe->chan);
2639 if (!(ds = ast_channel_datastore_alloc(&queue_transfer_info, NULL))) {
2640 ast_channel_unlock(qe->chan);
2641 ast_log(LOG_WARNING, "Unable to create transfer datastore. queue_log will not show attended transfer\n");
2642 return;
2645 qtds->qe = qe;
2646 /* This member is refcounted in try_calling, so no need to add it here, too */
2647 qtds->member = member;
2648 qtds->starttime = starttime;
2649 ds->data = qtds;
2650 ast_channel_datastore_add(qe->chan, ds);
2651 ast_channel_unlock(qe->chan);
2655 /*! \brief A large function which calls members, updates statistics, and bridges the caller and a member
2657 * Here is the process of this function
2658 * 1. Process any options passed to the Queue() application. Options here mean the third argument to Queue()
2659 * 2. Iterate trough the members of the queue, creating a callattempt corresponding to each member. During this
2660 * iteration, we also check the dialed_interfaces datastore to see if we have already attempted calling this
2661 * member. If we have, we do not create a callattempt. This is in place to prevent call forwarding loops. Also
2662 * during each iteration, we call calc_metric to determine which members should be rung when.
2663 * 3. Call ring_one to place a call to the appropriate member(s)
2664 * 4. Call wait_for_answer to wait for an answer. If no one answers, return.
2665 * 5. Take care of any holdtime announcements, member delays, or other options which occur after a call has been answered.
2666 * 6. Start the monitor or mixmonitor if the option is set
2667 * 7. Remove the caller from the queue to allow other callers to advance
2668 * 8. Bridge the call.
2669 * 9. Do any post processing after the call has disconnected.
2671 * \param[in] qe the queue_ent structure which corresponds to the caller attempting to reach members
2672 * \param[in] options the options passed as the third parameter to the Queue() application
2673 * \param[in] url the url passed as the fourth parameter to the Queue() application
2674 * \param[in,out] tries the number of times we have tried calling queue members
2675 * \param[out] noption set if the call to Queue() has the 'n' option set.
2676 * \param[in] agi the agi passed as the fifth parameter to the Queue() application
2679 static int try_calling(struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *tries, int *noption, const char *agi)
2681 struct member *cur;
2682 struct callattempt *outgoing = NULL; /* the list of calls we are building */
2683 int to;
2684 char oldexten[AST_MAX_EXTENSION]="";
2685 char oldcontext[AST_MAX_CONTEXT]="";
2686 char queuename[256]="";
2687 struct ast_channel *peer;
2688 struct ast_channel *which;
2689 struct callattempt *lpeer;
2690 struct member *member;
2691 struct ast_app *app;
2692 int res = 0, bridge = 0;
2693 int numbusies = 0;
2694 int x=0;
2695 char *announce = NULL;
2696 char digit = 0;
2697 time_t callstart;
2698 time_t now = time(NULL);
2699 struct ast_bridge_config bridge_config;
2700 char nondataquality = 1;
2701 char *agiexec = NULL;
2702 int ret = 0;
2703 const char *monitorfilename;
2704 const char *monitor_exec;
2705 const char *monitor_options;
2706 char tmpid[256], tmpid2[256];
2707 char meid[1024], meid2[1024];
2708 char mixmonargs[1512];
2709 struct ast_app *mixmonapp = NULL;
2710 char *p;
2711 char vars[2048];
2712 int forwardsallowed = 1;
2713 int callcompletedinsl;
2714 struct ao2_iterator memi;
2715 struct ast_datastore *datastore;
2717 ast_channel_lock(qe->chan);
2718 datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL);
2719 ast_channel_unlock(qe->chan);
2721 memset(&bridge_config, 0, sizeof(bridge_config));
2722 time(&now);
2724 /* If we've already exceeded our timeout, then just stop
2725 * This should be extremely rare. queue_exec will take care
2726 * of removing the caller and reporting the timeout as the reason.
2728 if (qe->expire && now >= qe->expire) {
2729 res = 0;
2730 goto out;
2733 for (; options && *options; options++)
2734 switch (*options) {
2735 case 't':
2736 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
2737 break;
2738 case 'T':
2739 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
2740 break;
2741 case 'w':
2742 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
2743 break;
2744 case 'W':
2745 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
2746 break;
2747 case 'd':
2748 nondataquality = 0;
2749 break;
2750 case 'h':
2751 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
2752 break;
2753 case 'H':
2754 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
2755 break;
2756 case 'n':
2757 if (qe->parent->strategy == QUEUE_STRATEGY_ROUNDROBIN || qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY)
2758 (*tries)++;
2759 else
2760 *tries = qe->parent->membercount;
2761 *noption = 1;
2762 break;
2763 case 'i':
2764 forwardsallowed = 0;
2765 break;
2768 /* Hold the lock while we setup the outgoing calls */
2769 if (use_weight)
2770 AST_LIST_LOCK(&queues);
2771 ast_mutex_lock(&qe->parent->lock);
2772 if (option_debug)
2773 ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n",
2774 qe->chan->name);
2775 ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
2776 if (!ast_strlen_zero(qe->announce))
2777 announce = qe->announce;
2778 if (!ast_strlen_zero(announceoverride))
2779 announce = announceoverride;
2781 memi = ao2_iterator_init(qe->parent->members, 0);
2782 while ((cur = ao2_iterator_next(&memi))) {
2783 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
2784 struct ast_dialed_interface *di;
2785 AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces;
2786 if (!tmp) {
2787 ao2_ref(cur, -1);
2788 ast_mutex_unlock(&qe->parent->lock);
2789 if (use_weight)
2790 AST_LIST_UNLOCK(&queues);
2791 goto out;
2793 if (!datastore) {
2794 if (!(datastore = ast_channel_datastore_alloc(&dialed_interface_info, NULL))) {
2795 ao2_ref(cur, -1);
2796 ast_mutex_unlock(&qe->parent->lock);
2797 if (use_weight)
2798 AST_LIST_UNLOCK(&queues);
2799 free(tmp);
2800 goto out;
2802 datastore->inheritance = DATASTORE_INHERIT_FOREVER;
2803 if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) {
2804 ao2_ref(cur, -1);
2805 ast_mutex_unlock(&qe->parent->lock);
2806 if (use_weight)
2807 AST_LIST_UNLOCK(&queues);
2808 free(tmp);
2809 goto out;
2811 datastore->data = dialed_interfaces;
2812 AST_LIST_HEAD_INIT(dialed_interfaces);
2814 ast_channel_lock(qe->chan);
2815 ast_channel_datastore_add(qe->chan, datastore);
2816 ast_channel_unlock(qe->chan);
2817 } else
2818 dialed_interfaces = datastore->data;
2820 AST_LIST_LOCK(dialed_interfaces);
2821 AST_LIST_TRAVERSE(dialed_interfaces, di, list) {
2822 if (!strcasecmp(cur->interface, di->interface)) {
2823 ast_log(LOG_DEBUG, "Skipping dialing interface '%s' since it has already been dialed\n",
2824 di->interface);
2825 break;
2828 AST_LIST_UNLOCK(dialed_interfaces);
2830 if (di) {
2831 free(tmp);
2832 continue;
2835 /* It is always ok to dial a Local interface. We only keep track of
2836 * which "real" interfaces have been dialed. The Local channel will
2837 * inherit this list so that if it ends up dialing a real interface,
2838 * it won't call one that has already been called. */
2839 if (strncasecmp(cur->interface, "Local/", 6)) {
2840 if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) {
2841 ao2_ref(cur, -1);
2842 ast_mutex_unlock(&qe->parent->lock);
2843 if (use_weight)
2844 AST_LIST_UNLOCK(&queues);
2845 free(tmp);
2846 goto out;
2848 strcpy(di->interface, cur->interface);
2850 AST_LIST_LOCK(dialed_interfaces);
2851 AST_LIST_INSERT_TAIL(dialed_interfaces, di, list);
2852 AST_LIST_UNLOCK(dialed_interfaces);
2855 tmp->stillgoing = -1;
2856 tmp->member = cur;
2857 tmp->oldstatus = cur->status;
2858 tmp->lastcall = cur->lastcall;
2859 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
2860 /* Special case: If we ring everyone, go ahead and ring them, otherwise
2861 just calculate their metric for the appropriate strategy */
2862 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
2863 /* Put them in the list of outgoing thingies... We're ready now.
2864 XXX If we're forcibly removed, these outgoing calls won't get
2865 hung up XXX */
2866 tmp->q_next = outgoing;
2867 outgoing = tmp;
2868 /* If this line is up, don't try anybody else */
2869 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
2870 break;
2871 } else {
2872 ao2_ref(cur, -1);
2873 free(tmp);
2876 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout))
2877 to = (qe->expire - now) * 1000;
2878 else
2879 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
2880 ++qe->pending;
2881 ast_mutex_unlock(&qe->parent->lock);
2882 ring_one(qe, outgoing, &numbusies);
2883 if (use_weight)
2884 AST_LIST_UNLOCK(&queues);
2885 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed);
2886 /* The ast_channel_datastore_remove() function could fail here if the
2887 * datastore was moved to another channel during a masquerade. If this is
2888 * the case, don't free the datastore here because later, when the channel
2889 * to which the datastore was moved hangs up, it will attempt to free this
2890 * datastore again, causing a crash
2892 if (datastore && !ast_channel_datastore_remove(qe->chan, datastore)) {
2893 ast_channel_datastore_free(datastore);
2895 ast_mutex_lock(&qe->parent->lock);
2896 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
2897 store_next(qe, outgoing);
2899 ast_mutex_unlock(&qe->parent->lock);
2900 peer = lpeer ? lpeer->chan : NULL;
2901 if (!peer) {
2902 qe->pending = 0;
2903 if (to) {
2904 /* Must gotten hung up */
2905 res = -1;
2906 } else {
2907 /* User exited by pressing a digit */
2908 res = digit;
2910 if (option_debug && res == -1)
2911 ast_log(LOG_DEBUG, "%s: Nobody answered.\n", qe->chan->name);
2912 } else { /* peer is valid */
2913 /* Ah ha! Someone answered within the desired timeframe. Of course after this
2914 we will always return with -1 so that it is hung up properly after the
2915 conversation. */
2916 if (!strcmp(qe->chan->tech->type, "Zap"))
2917 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2918 if (!strcmp(peer->tech->type, "Zap"))
2919 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2920 /* Update parameters for the queue */
2921 time(&now);
2922 recalc_holdtime(qe, (now - qe->start));
2923 ast_mutex_lock(&qe->parent->lock);
2924 callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel);
2925 ast_mutex_unlock(&qe->parent->lock);
2926 member = lpeer->member;
2927 /* Increment the refcount for this member, since we're going to be using it for awhile in here. */
2928 ao2_ref(member, 1);
2929 hangupcalls(outgoing, peer);
2930 outgoing = NULL;
2931 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
2932 int res2;
2934 res2 = ast_autoservice_start(qe->chan);
2935 if (!res2) {
2936 if (qe->parent->memberdelay) {
2937 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
2938 res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
2940 if (!res2 && announce) {
2941 play_file(peer, announce);
2943 if (!res2 && qe->parent->reportholdtime) {
2944 if (!play_file(peer, qe->parent->sound_reporthold)) {
2945 int holdtime;
2947 time(&now);
2948 holdtime = abs((now - qe->start) / 60);
2949 if (holdtime < 2) {
2950 play_file(peer, qe->parent->sound_lessthan);
2951 ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL);
2952 } else
2953 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
2954 play_file(peer, qe->parent->sound_minutes);
2958 res2 |= ast_autoservice_stop(qe->chan);
2959 if (peer->_softhangup) {
2960 /* Agent must have hung up */
2961 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", peer->name);
2962 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", "");
2963 if (qe->parent->eventwhencalled)
2964 manager_event(EVENT_FLAG_AGENT, "AgentDump",
2965 "Queue: %s\r\n"
2966 "Uniqueid: %s\r\n"
2967 "Channel: %s\r\n"
2968 "Member: %s\r\n"
2969 "MemberName: %s\r\n"
2970 "%s",
2971 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
2972 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
2973 ast_hangup(peer);
2974 ao2_ref(member, -1);
2975 goto out;
2976 } else if (res2) {
2977 /* Caller must have hung up just before being connected*/
2978 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
2979 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
2980 record_abandoned(qe);
2981 ast_hangup(peer);
2982 ao2_ref(member, -1);
2983 return -1;
2986 /* Stop music on hold */
2987 ast_moh_stop(qe->chan);
2988 /* If appropriate, log that we have a destination channel */
2989 if (qe->chan->cdr)
2990 ast_cdr_setdestchan(qe->chan->cdr, peer->name);
2991 /* Make sure channels are compatible */
2992 res = ast_channel_make_compatible(qe->chan, peer);
2993 if (res < 0) {
2994 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", "");
2995 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
2996 record_abandoned(qe);
2997 ast_hangup(peer);
2998 ao2_ref(member, -1);
2999 return -1;
3002 if (qe->parent->setinterfacevar)
3003 pbx_builtin_setvar_helper(qe->chan, "MEMBERINTERFACE", member->interface);
3005 /* Begin Monitoring */
3006 if (qe->parent->monfmt && *qe->parent->monfmt) {
3007 if (!qe->parent->montype) {
3008 if (option_debug)
3009 ast_log(LOG_DEBUG, "Starting Monitor as requested.\n");
3010 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
3011 if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))
3012 which = qe->chan;
3013 else
3014 which = peer;
3015 if (monitorfilename)
3016 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 );
3017 else if (qe->chan->cdr)
3018 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
3019 else {
3020 /* Last ditch effort -- no CDR, make up something */
3021 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
3022 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 );
3024 if (qe->parent->monjoin)
3025 ast_monitor_setjoinfiles(which, 1);
3026 } else {
3027 if (option_debug)
3028 ast_log(LOG_DEBUG, "Starting MixMonitor as requested.\n");
3029 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
3030 if (!monitorfilename) {
3031 if (qe->chan->cdr)
3032 ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid)-1);
3033 else
3034 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
3035 } else {
3036 ast_copy_string(tmpid2, monitorfilename, sizeof(tmpid2)-1);
3037 for (p = tmpid2; *p ; p++) {
3038 if (*p == '^' && *(p+1) == '{') {
3039 *p = '$';
3043 memset(tmpid, 0, sizeof(tmpid));
3044 pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1);
3047 monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC");
3048 monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS");
3050 if (monitor_exec) {
3051 ast_copy_string(meid2, monitor_exec, sizeof(meid2)-1);
3052 for (p = meid2; *p ; p++) {
3053 if (*p == '^' && *(p+1) == '{') {
3054 *p = '$';
3058 memset(meid, 0, sizeof(meid));
3059 pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1);
3062 snprintf(tmpid2, sizeof(tmpid2)-1, "%s.%s", tmpid, qe->parent->monfmt);
3064 mixmonapp = pbx_findapp("MixMonitor");
3066 if (strchr(tmpid2, '|')) {
3067 ast_log(LOG_WARNING, "monitor-format (in queues.conf) and MONITOR_FILENAME cannot contain a '|'! Not recording.\n");
3068 mixmonapp = NULL;
3071 if (!monitor_options)
3072 monitor_options = "";
3074 if (strchr(monitor_options, '|')) {
3075 ast_log(LOG_WARNING, "MONITOR_OPTIONS cannot contain a '|'! Not recording.\n");
3076 mixmonapp = NULL;
3079 if (mixmonapp) {
3080 if (!ast_strlen_zero(monitor_exec))
3081 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s|%s", tmpid2, monitor_options, monitor_exec);
3082 else
3083 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s", tmpid2, monitor_options);
3085 if (option_debug)
3086 ast_log(LOG_DEBUG, "Arguments being passed to MixMonitor: %s\n", mixmonargs);
3087 /* We purposely lock the CDR so that pbx_exec does not update the application data */
3088 if (qe->chan->cdr)
3089 ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
3090 ret = pbx_exec(qe->chan, mixmonapp, mixmonargs);
3091 if (qe->chan->cdr)
3092 ast_clear_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
3094 } else
3095 ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n");
3099 /* Drop out of the queue at this point, to prepare for next caller */
3100 leave_queue(qe);
3101 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
3102 if (option_debug)
3103 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
3104 ast_channel_sendurl(peer, url);
3106 if (!ast_strlen_zero(agi)) {
3107 if (option_debug)
3108 ast_log(LOG_DEBUG, "app_queue: agi=%s.\n", agi);
3109 app = pbx_findapp("agi");
3110 if (app) {
3111 agiexec = ast_strdupa(agi);
3112 ret = pbx_exec(qe->chan, app, agiexec);
3113 } else
3114 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
3116 qe->handled++;
3117 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s", (long)time(NULL) - qe->start, peer->uniqueid);
3118 if (qe->parent->eventwhencalled)
3119 manager_event(EVENT_FLAG_AGENT, "AgentConnect",
3120 "Queue: %s\r\n"
3121 "Uniqueid: %s\r\n"
3122 "Channel: %s\r\n"
3123 "Member: %s\r\n"
3124 "MemberName: %s\r\n"
3125 "Holdtime: %ld\r\n"
3126 "BridgedChannel: %s\r\n"
3127 "%s",
3128 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
3129 (long)time(NULL) - qe->start, peer->uniqueid,
3130 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
3131 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
3132 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
3133 time(&callstart);
3135 if (member->status == AST_DEVICE_NOT_INUSE)
3136 ast_log(LOG_WARNING, "The device state of this queue member, %s, is still 'Not in Use' when it probably should not be! Please check UPGRADE.txt for correct configuration settings.\n", member->membername);
3138 setup_transfer_datastore(qe, member, callstart);
3139 bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
3141 if (!attended_transfer_occurred(qe->chan)) {
3142 struct ast_datastore *transfer_ds;
3143 if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
3144 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld",
3145 qe->chan->exten, qe->chan->context, (long) (callstart - qe->start),
3146 (long) (time(NULL) - callstart));
3147 } else if (qe->chan->_softhangup) {
3148 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d",
3149 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
3150 if (qe->parent->eventwhencalled)
3151 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
3152 "Queue: %s\r\n"
3153 "Uniqueid: %s\r\n"
3154 "Channel: %s\r\n"
3155 "Member: %s\r\n"
3156 "MemberName: %s\r\n"
3157 "HoldTime: %ld\r\n"
3158 "TalkTime: %ld\r\n"
3159 "Reason: caller\r\n"
3160 "%s",
3161 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
3162 (long)(callstart - qe->start), (long)(time(NULL) - callstart),
3163 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
3164 } else {
3165 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d",
3166 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
3167 if (qe->parent->eventwhencalled)
3168 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
3169 "Queue: %s\r\n"
3170 "Uniqueid: %s\r\n"
3171 "Channel: %s\r\n"
3172 "MemberName: %s\r\n"
3173 "HoldTime: %ld\r\n"
3174 "TalkTime: %ld\r\n"
3175 "Reason: agent\r\n"
3176 "%s",
3177 queuename, qe->chan->uniqueid, peer->name, member->membername, (long)(callstart - qe->start),
3178 (long)(time(NULL) - callstart),
3179 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
3181 ast_channel_lock(qe->chan);
3182 transfer_ds = ast_channel_datastore_find(qe->chan, &queue_transfer_info, NULL);
3183 if (transfer_ds) {
3184 ast_channel_datastore_remove(qe->chan, transfer_ds);
3185 ast_channel_datastore_free(transfer_ds);
3187 ast_channel_unlock(qe->chan);
3190 if (bridge != AST_PBX_NO_HANGUP_PEER)
3191 ast_hangup(peer);
3192 update_queue(qe->parent, member, callcompletedinsl);
3193 res = bridge ? bridge : 1;
3194 ao2_ref(member, -1);
3196 out:
3197 hangupcalls(outgoing, NULL);
3199 return res;
3202 static int wait_a_bit(struct queue_ent *qe)
3204 /* Don't need to hold the lock while we setup the outgoing calls */
3205 int retrywait = qe->parent->retry * 1000;
3207 int res = ast_waitfordigit(qe->chan, retrywait);
3208 if (res > 0 && !valid_exit(qe, res))
3209 res = 0;
3211 return res;
3214 static struct member *interface_exists(struct call_queue *q, const char *interface)
3216 struct member *mem;
3217 struct ao2_iterator mem_iter;
3219 if (!q)
3220 return NULL;
3222 mem_iter = ao2_iterator_init(q->members, 0);
3223 while ((mem = ao2_iterator_next(&mem_iter))) {
3224 if (!strcasecmp(interface, mem->interface))
3225 return mem;
3226 ao2_ref(mem, -1);
3229 return NULL;
3233 /* Dump all members in a specific queue to the database
3235 * <pm_family>/<queuename> = <interface>;<penalty>;<paused>[|...]
3238 static void dump_queue_members(struct call_queue *pm_queue)
3240 struct member *cur_member;
3241 char value[PM_MAX_LEN];
3242 int value_len = 0;
3243 int res;
3244 struct ao2_iterator mem_iter;
3246 memset(value, 0, sizeof(value));
3248 if (!pm_queue)
3249 return;
3251 mem_iter = ao2_iterator_init(pm_queue->members, 0);
3252 while ((cur_member = ao2_iterator_next(&mem_iter))) {
3253 if (!cur_member->dynamic) {
3254 ao2_ref(cur_member, -1);
3255 continue;
3258 res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s",
3259 value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername);
3261 ao2_ref(cur_member, -1);
3263 if (res != strlen(value + value_len)) {
3264 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
3265 break;
3267 value_len += res;
3270 if (value_len && !cur_member) {
3271 if (ast_db_put(pm_family, pm_queue->name, value))
3272 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
3273 } else
3274 /* Delete the entry if the queue is empty or there is an error */
3275 ast_db_del(pm_family, pm_queue->name);
3278 static int remove_from_queue(const char *queuename, const char *interface)
3280 struct call_queue *q;
3281 struct member *mem, tmpmem;
3282 int res = RES_NOSUCHQUEUE;
3284 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
3286 AST_LIST_LOCK(&queues);
3287 AST_LIST_TRAVERSE(&queues, q, list) {
3288 ast_mutex_lock(&q->lock);
3289 if (strcmp(q->name, queuename)) {
3290 ast_mutex_unlock(&q->lock);
3291 continue;
3294 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
3295 /* XXX future changes should beware of this assumption!! */
3296 if (!mem->dynamic) {
3297 res = RES_NOT_DYNAMIC;
3298 ao2_ref(mem, -1);
3299 ast_mutex_unlock(&q->lock);
3300 break;
3302 q->membercount--;
3303 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
3304 "Queue: %s\r\n"
3305 "Location: %s\r\n"
3306 "MemberName: %s\r\n",
3307 q->name, mem->interface, mem->membername);
3308 ao2_unlink(q->members, mem);
3309 ao2_ref(mem, -1);
3311 if (queue_persistent_members)
3312 dump_queue_members(q);
3314 res = RES_OKAY;
3315 } else {
3316 res = RES_EXISTS;
3318 ast_mutex_unlock(&q->lock);
3319 break;
3322 if (res == RES_OKAY)
3323 remove_from_interfaces(interface);
3325 AST_LIST_UNLOCK(&queues);
3327 return res;
3331 static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump)
3333 struct call_queue *q;
3334 struct member *new_member, *old_member;
3335 int res = RES_NOSUCHQUEUE;
3337 /* \note Ensure the appropriate realtime queue is loaded. Note that this
3338 * short-circuits if the queue is already in memory. */
3339 if (!(q = load_realtime_queue(queuename)))
3340 return res;
3342 AST_LIST_LOCK(&queues);
3344 ast_mutex_lock(&q->lock);
3345 if ((old_member = interface_exists(q, interface)) == NULL) {
3346 add_to_interfaces(interface);
3347 if ((new_member = create_queue_member(interface, membername, penalty, paused))) {
3348 new_member->dynamic = 1;
3349 ao2_link(q->members, new_member);
3350 q->membercount++;
3351 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
3352 "Queue: %s\r\n"
3353 "Location: %s\r\n"
3354 "MemberName: %s\r\n"
3355 "Membership: %s\r\n"
3356 "Penalty: %d\r\n"
3357 "CallsTaken: %d\r\n"
3358 "LastCall: %d\r\n"
3359 "Status: %d\r\n"
3360 "Paused: %d\r\n",
3361 q->name, new_member->interface, new_member->membername,
3362 "dynamic",
3363 new_member->penalty, new_member->calls, (int) new_member->lastcall,
3364 new_member->status, new_member->paused);
3366 ao2_ref(new_member, -1);
3367 new_member = NULL;
3369 if (dump)
3370 dump_queue_members(q);
3372 res = RES_OKAY;
3373 } else {
3374 res = RES_OUTOFMEMORY;
3376 } else {
3377 ao2_ref(old_member, -1);
3378 res = RES_EXISTS;
3380 ast_mutex_unlock(&q->lock);
3381 AST_LIST_UNLOCK(&queues);
3383 return res;
3386 static int set_member_paused(const char *queuename, const char *interface, int paused)
3388 int found = 0;
3389 struct call_queue *q;
3390 struct member *mem;
3392 /* Special event for when all queues are paused - individual events still generated */
3393 /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */
3394 if (ast_strlen_zero(queuename))
3395 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
3397 AST_LIST_LOCK(&queues);
3398 AST_LIST_TRAVERSE(&queues, q, list) {
3399 ast_mutex_lock(&q->lock);
3400 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
3401 if ((mem = interface_exists(q, interface))) {
3402 found++;
3403 if (mem->paused == paused)
3404 ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
3405 mem->paused = paused;
3407 if (queue_persistent_members)
3408 dump_queue_members(q);
3410 if (mem->realtime)
3411 update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0");
3413 ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", "");
3415 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
3416 "Queue: %s\r\n"
3417 "Location: %s\r\n"
3418 "MemberName: %s\r\n"
3419 "Paused: %d\r\n",
3420 q->name, mem->interface, mem->membername, paused);
3421 ao2_ref(mem, -1);
3424 ast_mutex_unlock(&q->lock);
3426 AST_LIST_UNLOCK(&queues);
3428 return found ? RESULT_SUCCESS : RESULT_FAILURE;
3431 /* Reload dynamic queue members persisted into the astdb */
3432 static void reload_queue_members(void)
3434 char *cur_ptr;
3435 char *queue_name;
3436 char *member;
3437 char *interface;
3438 char *membername = NULL;
3439 char *penalty_tok;
3440 int penalty = 0;
3441 char *paused_tok;
3442 int paused = 0;
3443 struct ast_db_entry *db_tree;
3444 struct ast_db_entry *entry;
3445 struct call_queue *cur_queue;
3446 char queue_data[PM_MAX_LEN];
3448 AST_LIST_LOCK(&queues);
3450 /* Each key in 'pm_family' is the name of a queue */
3451 db_tree = ast_db_gettree(pm_family, NULL);
3452 for (entry = db_tree; entry; entry = entry->next) {
3454 queue_name = entry->key + strlen(pm_family) + 2;
3456 AST_LIST_TRAVERSE(&queues, cur_queue, list) {
3457 ast_mutex_lock(&cur_queue->lock);
3458 if (!strcmp(queue_name, cur_queue->name))
3459 break;
3460 ast_mutex_unlock(&cur_queue->lock);
3463 if (!cur_queue)
3464 cur_queue = load_realtime_queue(queue_name);
3466 if (!cur_queue) {
3467 /* If the queue no longer exists, remove it from the
3468 * database */
3469 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
3470 ast_db_del(pm_family, queue_name);
3471 continue;
3472 } else
3473 ast_mutex_unlock(&cur_queue->lock);
3475 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN))
3476 continue;
3478 cur_ptr = queue_data;
3479 while ((member = strsep(&cur_ptr, "|"))) {
3480 if (ast_strlen_zero(member))
3481 continue;
3483 interface = strsep(&member, ";");
3484 penalty_tok = strsep(&member, ";");
3485 paused_tok = strsep(&member, ";");
3486 membername = strsep(&member, ";");
3488 if (!penalty_tok) {
3489 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
3490 break;
3492 penalty = strtol(penalty_tok, NULL, 10);
3493 if (errno == ERANGE) {
3494 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
3495 break;
3498 if (!paused_tok) {
3499 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
3500 break;
3502 paused = strtol(paused_tok, NULL, 10);
3503 if ((errno == ERANGE) || paused < 0 || paused > 1) {
3504 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
3505 break;
3507 if (ast_strlen_zero(membername))
3508 membername = interface;
3510 if (option_debug)
3511 ast_log(LOG_DEBUG, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name, interface, membername, penalty, paused);
3513 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0) == RES_OUTOFMEMORY) {
3514 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
3515 break;
3520 AST_LIST_UNLOCK(&queues);
3521 if (db_tree) {
3522 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
3523 ast_db_freetree(db_tree);
3527 static int pqm_exec(struct ast_channel *chan, void *data)
3529 struct ast_module_user *lu;
3530 char *parse;
3531 int priority_jump = 0;
3532 AST_DECLARE_APP_ARGS(args,
3533 AST_APP_ARG(queuename);
3534 AST_APP_ARG(interface);
3535 AST_APP_ARG(options);
3538 if (ast_strlen_zero(data)) {
3539 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface[|options])\n");
3540 return -1;
3543 parse = ast_strdupa(data);
3545 AST_STANDARD_APP_ARGS(args, parse);
3547 lu = ast_module_user_add(chan);
3549 if (args.options) {
3550 if (strchr(args.options, 'j'))
3551 priority_jump = 1;
3554 if (ast_strlen_zero(args.interface)) {
3555 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
3556 ast_module_user_remove(lu);
3557 return -1;
3560 if (set_member_paused(args.queuename, args.interface, 1)) {
3561 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
3562 if (priority_jump || ast_opt_priority_jumping) {
3563 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
3564 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
3565 ast_module_user_remove(lu);
3566 return 0;
3569 ast_module_user_remove(lu);
3570 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
3571 return 0;
3574 ast_module_user_remove(lu);
3575 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
3577 return 0;
3580 static int upqm_exec(struct ast_channel *chan, void *data)
3582 struct ast_module_user *lu;
3583 char *parse;
3584 int priority_jump = 0;
3585 AST_DECLARE_APP_ARGS(args,
3586 AST_APP_ARG(queuename);
3587 AST_APP_ARG(interface);
3588 AST_APP_ARG(options);
3591 if (ast_strlen_zero(data)) {
3592 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface[|options])\n");
3593 return -1;
3596 parse = ast_strdupa(data);
3598 AST_STANDARD_APP_ARGS(args, parse);
3600 lu = ast_module_user_add(chan);
3602 if (args.options) {
3603 if (strchr(args.options, 'j'))
3604 priority_jump = 1;
3607 if (ast_strlen_zero(args.interface)) {
3608 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
3609 ast_module_user_remove(lu);
3610 return -1;
3613 if (set_member_paused(args.queuename, args.interface, 0)) {
3614 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
3615 if (priority_jump || ast_opt_priority_jumping) {
3616 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
3617 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
3618 ast_module_user_remove(lu);
3619 return 0;
3622 ast_module_user_remove(lu);
3623 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
3624 return 0;
3627 ast_module_user_remove(lu);
3628 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
3630 return 0;
3633 static int rqm_exec(struct ast_channel *chan, void *data)
3635 int res=-1;
3636 struct ast_module_user *lu;
3637 char *parse, *temppos = NULL;
3638 int priority_jump = 0;
3639 AST_DECLARE_APP_ARGS(args,
3640 AST_APP_ARG(queuename);
3641 AST_APP_ARG(interface);
3642 AST_APP_ARG(options);
3646 if (ast_strlen_zero(data)) {
3647 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n");
3648 return -1;
3651 parse = ast_strdupa(data);
3653 AST_STANDARD_APP_ARGS(args, parse);
3655 lu = ast_module_user_add(chan);
3657 if (ast_strlen_zero(args.interface)) {
3658 args.interface = ast_strdupa(chan->name);
3659 temppos = strrchr(args.interface, '-');
3660 if (temppos)
3661 *temppos = '\0';
3664 if (args.options) {
3665 if (strchr(args.options, 'j'))
3666 priority_jump = 1;
3669 switch (remove_from_queue(args.queuename, args.interface)) {
3670 case RES_OKAY:
3671 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", "");
3672 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
3673 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
3674 res = 0;
3675 break;
3676 case RES_EXISTS:
3677 ast_log(LOG_DEBUG, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
3678 if (priority_jump || ast_opt_priority_jumping)
3679 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
3680 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
3681 res = 0;
3682 break;
3683 case RES_NOSUCHQUEUE:
3684 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
3685 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
3686 res = 0;
3687 break;
3688 case RES_NOT_DYNAMIC:
3689 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface);
3690 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC");
3691 res = 0;
3692 break;
3695 ast_module_user_remove(lu);
3697 return res;
3700 static int aqm_exec(struct ast_channel *chan, void *data)
3702 int res=-1;
3703 struct ast_module_user *lu;
3704 char *parse, *temppos = NULL;
3705 int priority_jump = 0;
3706 AST_DECLARE_APP_ARGS(args,
3707 AST_APP_ARG(queuename);
3708 AST_APP_ARG(interface);
3709 AST_APP_ARG(penalty);
3710 AST_APP_ARG(options);
3711 AST_APP_ARG(membername);
3713 int penalty = 0;
3715 if (ast_strlen_zero(data)) {
3716 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface]|[penalty][|options][|membername]])\n");
3717 return -1;
3720 parse = ast_strdupa(data);
3722 AST_STANDARD_APP_ARGS(args, parse);
3724 lu = ast_module_user_add(chan);
3726 if (ast_strlen_zero(args.interface)) {
3727 args.interface = ast_strdupa(chan->name);
3728 temppos = strrchr(args.interface, '-');
3729 if (temppos)
3730 *temppos = '\0';
3733 if (!ast_strlen_zero(args.penalty)) {
3734 if ((sscanf(args.penalty, "%d", &penalty) != 1) || penalty < 0) {
3735 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
3736 penalty = 0;
3740 if (args.options) {
3741 if (strchr(args.options, 'j'))
3742 priority_jump = 1;
3745 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members)) {
3746 case RES_OKAY:
3747 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", "");
3748 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
3749 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
3750 res = 0;
3751 break;
3752 case RES_EXISTS:
3753 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
3754 if (priority_jump || ast_opt_priority_jumping)
3755 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
3756 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
3757 res = 0;
3758 break;
3759 case RES_NOSUCHQUEUE:
3760 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
3761 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
3762 res = 0;
3763 break;
3764 case RES_OUTOFMEMORY:
3765 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename);
3766 break;
3769 ast_module_user_remove(lu);
3771 return res;
3774 static int ql_exec(struct ast_channel *chan, void *data)
3776 struct ast_module_user *u;
3777 char *parse;
3779 AST_DECLARE_APP_ARGS(args,
3780 AST_APP_ARG(queuename);
3781 AST_APP_ARG(uniqueid);
3782 AST_APP_ARG(membername);
3783 AST_APP_ARG(event);
3784 AST_APP_ARG(params);
3787 if (ast_strlen_zero(data)) {
3788 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo]\n");
3789 return -1;
3792 u = ast_module_user_add(chan);
3794 parse = ast_strdupa(data);
3796 AST_STANDARD_APP_ARGS(args, parse);
3798 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
3799 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
3800 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo])\n");
3801 ast_module_user_remove(u);
3802 return -1;
3805 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event,
3806 "%s", args.params ? args.params : "");
3808 ast_module_user_remove(u);
3810 return 0;
3813 /*!\brief The starting point for all queue calls
3815 * The process involved here is to
3816 * 1. Parse the options specified in the call to Queue()
3817 * 2. Join the queue
3818 * 3. Wait in a loop until it is our turn to try calling a queue member
3819 * 4. Attempt to call a queue member
3820 * 5. If 4. did not result in a bridged call, then check for between
3821 * call options such as periodic announcements etc.
3822 * 6. Try 4 again uless some condition (such as an expiration time) causes us to
3823 * exit the queue.
3825 static int queue_exec(struct ast_channel *chan, void *data)
3827 int res=-1;
3828 int ringing=0;
3829 struct ast_module_user *lu;
3830 const char *user_priority;
3831 const char *max_penalty_str;
3832 int prio;
3833 int max_penalty;
3834 enum queue_result reason = QUEUE_UNKNOWN;
3835 /* whether to exit Queue application after the timeout hits */
3836 int tries = 0;
3837 int noption = 0;
3838 char *parse;
3839 AST_DECLARE_APP_ARGS(args,
3840 AST_APP_ARG(queuename);
3841 AST_APP_ARG(options);
3842 AST_APP_ARG(url);
3843 AST_APP_ARG(announceoverride);
3844 AST_APP_ARG(queuetimeoutstr);
3845 AST_APP_ARG(agi);
3847 /* Our queue entry */
3848 struct queue_ent qe;
3850 if (ast_strlen_zero(data)) {
3851 ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL[|announceoverride[|timeout[|agi]]]]]\n");
3852 return -1;
3855 parse = ast_strdupa(data);
3856 AST_STANDARD_APP_ARGS(args, parse);
3858 lu = ast_module_user_add(chan);
3860 /* Setup our queue entry */
3861 memset(&qe, 0, sizeof(qe));
3862 qe.start = time(NULL);
3864 /* set the expire time based on the supplied timeout; */
3865 if (!ast_strlen_zero(args.queuetimeoutstr))
3866 qe.expire = qe.start + atoi(args.queuetimeoutstr);
3867 else
3868 qe.expire = 0;
3870 /* Get the priority from the variable ${QUEUE_PRIO} */
3871 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
3872 if (user_priority) {
3873 if (sscanf(user_priority, "%d", &prio) == 1) {
3874 if (option_debug)
3875 ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
3876 chan->name, prio);
3877 } else {
3878 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
3879 user_priority, chan->name);
3880 prio = 0;
3882 } else {
3883 if (option_debug > 2)
3884 ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n");
3885 prio = 0;
3888 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
3889 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
3890 if (sscanf(max_penalty_str, "%d", &max_penalty) == 1) {
3891 if (option_debug)
3892 ast_log(LOG_DEBUG, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n",
3893 chan->name, max_penalty);
3894 } else {
3895 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
3896 max_penalty_str, chan->name);
3897 max_penalty = 0;
3899 } else {
3900 max_penalty = 0;
3903 if (args.options && (strchr(args.options, 'r')))
3904 ringing = 1;
3906 if (option_debug)
3907 ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
3908 args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio);
3910 qe.chan = chan;
3911 qe.prio = prio;
3912 qe.max_penalty = max_penalty;
3913 qe.last_pos_said = 0;
3914 qe.last_pos = 0;
3915 qe.last_periodic_announce_time = time(NULL);
3916 qe.last_periodic_announce_sound = 0;
3917 qe.valid_digits = 0;
3918 if (!join_queue(args.queuename, &qe, &reason)) {
3919 int makeannouncement = 0;
3921 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", S_OR(args.url, ""),
3922 S_OR(chan->cid.cid_num, ""));
3923 check_turns:
3924 if (ringing) {
3925 ast_indicate(chan, AST_CONTROL_RINGING);
3926 } else {
3927 ast_moh_start(chan, qe.moh, NULL);
3930 /* This is the wait loop for callers 2 through maxlen */
3931 res = wait_our_turn(&qe, ringing, &reason);
3932 if (res)
3933 goto stop;
3935 for (;;) {
3936 /* This is the wait loop for the head caller*/
3937 /* To exit, they may get their call answered; */
3938 /* they may dial a digit from the queue context; */
3939 /* or, they may timeout. */
3941 enum queue_member_status stat;
3943 /* Leave if we have exceeded our queuetimeout */
3944 if (qe.expire && (time(NULL) >= qe.expire)) {
3945 record_abandoned(&qe);
3946 reason = QUEUE_TIMEOUT;
3947 res = 0;
3948 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
3949 break;
3952 if (makeannouncement) {
3953 /* Make a position announcement, if enabled */
3954 if (qe.parent->announcefrequency && !ringing)
3955 if ((res = say_position(&qe)))
3956 goto stop;
3959 makeannouncement = 1;
3961 /* Leave if we have exceeded our queuetimeout */
3962 if (qe.expire && (time(NULL) >= qe.expire)) {
3963 record_abandoned(&qe);
3964 reason = QUEUE_TIMEOUT;
3965 res = 0;
3966 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
3967 break;
3969 /* Make a periodic announcement, if enabled */
3970 if (qe.parent->periodicannouncefrequency && !ringing)
3971 if ((res = say_periodic_announcement(&qe)))
3972 goto stop;
3974 /* Leave if we have exceeded our queuetimeout */
3975 if (qe.expire && (time(NULL) >= qe.expire)) {
3976 record_abandoned(&qe);
3977 reason = QUEUE_TIMEOUT;
3978 res = 0;
3979 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
3980 break;
3982 /* Try calling all queue members for 'timeout' seconds */
3983 res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi);
3984 if (res)
3985 goto stop;
3987 stat = get_member_status(qe.parent, qe.max_penalty);
3989 /* exit after 'timeout' cycle if 'n' option enabled */
3990 if (noption && tries >= qe.parent->membercount) {
3991 if (option_verbose > 2)
3992 ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n");
3993 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
3994 record_abandoned(&qe);
3995 reason = QUEUE_TIMEOUT;
3996 res = 0;
3997 break;
4000 /* leave the queue if no agents, if enabled */
4001 if (qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
4002 record_abandoned(&qe);
4003 reason = QUEUE_LEAVEEMPTY;
4004 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
4005 res = 0;
4006 break;
4009 /* leave the queue if no reachable agents, if enabled */
4010 if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
4011 record_abandoned(&qe);
4012 reason = QUEUE_LEAVEUNAVAIL;
4013 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
4014 res = 0;
4015 break;
4018 /* Leave if we have exceeded our queuetimeout */
4019 if (qe.expire && (time(NULL) >= qe.expire)) {
4020 record_abandoned(&qe);
4021 reason = QUEUE_TIMEOUT;
4022 res = 0;
4023 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
4024 break;
4027 /* If using dynamic realtime members, we should regenerate the member list for this queue */
4028 update_realtime_members(qe.parent);
4030 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
4031 res = wait_a_bit(&qe);
4032 if (res)
4033 goto stop;
4035 /* Since this is a priority queue and
4036 * it is not sure that we are still at the head
4037 * of the queue, go and check for our turn again.
4039 if (!is_our_turn(&qe)) {
4040 if (option_debug)
4041 ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n",
4042 qe.chan->name);
4043 goto check_turns;
4047 stop:
4048 if (res) {
4049 if (res < 0) {
4050 if (!qe.handled) {
4051 record_abandoned(&qe);
4052 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON",
4053 "%d|%d|%ld", qe.pos, qe.opos,
4054 (long) time(NULL) - qe.start);
4056 res = -1;
4057 } else if (qe.valid_digits) {
4058 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY",
4059 "%s|%d", qe.digits, qe.pos);
4063 /* Don't allow return code > 0 */
4064 if (res >= 0 && res != AST_PBX_KEEPALIVE) {
4065 res = 0;
4066 if (ringing) {
4067 ast_indicate(chan, -1);
4068 } else {
4069 ast_moh_stop(chan);
4071 ast_stopstream(chan);
4073 leave_queue(&qe);
4074 if (reason != QUEUE_UNKNOWN)
4075 set_queue_result(chan, reason);
4076 } else {
4077 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
4078 set_queue_result(chan, reason);
4079 res = 0;
4081 ast_module_user_remove(lu);
4083 return res;
4086 static int queue_function_qac(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
4088 int count = 0;
4089 struct call_queue *q;
4090 struct ast_module_user *lu;
4091 struct member *m;
4092 struct ao2_iterator mem_iter;
4094 buf[0] = '\0';
4096 if (ast_strlen_zero(data)) {
4097 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
4098 return -1;
4101 lu = ast_module_user_add(chan);
4103 if ((q = load_realtime_queue(data))) {
4104 ast_mutex_lock(&q->lock);
4105 mem_iter = ao2_iterator_init(q->members, 0);
4106 while ((m = ao2_iterator_next(&mem_iter))) {
4107 /* Count the agents who are logged in and presently answering calls */
4108 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
4109 count++;
4111 ao2_ref(m, -1);
4113 ast_mutex_unlock(&q->lock);
4114 } else
4115 ast_log(LOG_WARNING, "queue %s was not found\n", data);
4117 snprintf(buf, len, "%d", count);
4118 ast_module_user_remove(lu);
4120 return 0;
4123 static int queue_function_queuewaitingcount(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
4125 int count = 0;
4126 struct call_queue *q;
4127 struct ast_module_user *lu;
4128 struct ast_variable *var = NULL;
4130 buf[0] = '\0';
4132 if (ast_strlen_zero(data)) {
4133 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
4134 return -1;
4137 lu = ast_module_user_add(chan);
4139 AST_LIST_LOCK(&queues);
4140 AST_LIST_TRAVERSE(&queues, q, list) {
4141 if (!strcasecmp(q->name, data)) {
4142 ast_mutex_lock(&q->lock);
4143 break;
4146 AST_LIST_UNLOCK(&queues);
4148 if (q) {
4149 count = q->count;
4150 ast_mutex_unlock(&q->lock);
4151 } else if ((var = ast_load_realtime("queues", "name", data, NULL))) {
4152 /* if the queue is realtime but was not found in memory, this
4153 * means that the queue had been deleted from memory since it was
4154 * "dead." This means it has a 0 waiting count
4156 count = 0;
4157 ast_variables_destroy(var);
4158 } else
4159 ast_log(LOG_WARNING, "queue %s was not found\n", data);
4161 snprintf(buf, len, "%d", count);
4162 ast_module_user_remove(lu);
4163 return 0;
4166 static int queue_function_queuememberlist(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
4168 struct ast_module_user *u;
4169 struct call_queue *q;
4170 struct member *m;
4172 /* Ensure an otherwise empty list doesn't return garbage */
4173 buf[0] = '\0';
4175 if (ast_strlen_zero(data)) {
4176 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
4177 return -1;
4180 u = ast_module_user_add(chan);
4182 AST_LIST_LOCK(&queues);
4183 AST_LIST_TRAVERSE(&queues, q, list) {
4184 if (!strcasecmp(q->name, data)) {
4185 ast_mutex_lock(&q->lock);
4186 break;
4189 AST_LIST_UNLOCK(&queues);
4191 if (q) {
4192 int buflen = 0, count = 0;
4193 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
4195 while ((m = ao2_iterator_next(&mem_iter))) {
4196 /* strcat() is always faster than printf() */
4197 if (count++) {
4198 strncat(buf + buflen, ",", len - buflen - 1);
4199 buflen++;
4201 strncat(buf + buflen, m->membername, len - buflen - 1);
4202 buflen += strlen(m->membername);
4203 /* Safeguard against overflow (negative length) */
4204 if (buflen >= len - 2) {
4205 ao2_ref(m, -1);
4206 ast_log(LOG_WARNING, "Truncating list\n");
4207 break;
4209 ao2_ref(m, -1);
4211 ast_mutex_unlock(&q->lock);
4212 } else
4213 ast_log(LOG_WARNING, "queue %s was not found\n", data);
4215 /* We should already be terminated, but let's make sure. */
4216 buf[len - 1] = '\0';
4217 ast_module_user_remove(u);
4219 return 0;
4222 static struct ast_custom_function queueagentcount_function = {
4223 .name = "QUEUEAGENTCOUNT",
4224 .synopsis = "Count number of agents answering a queue",
4225 .syntax = "QUEUEAGENTCOUNT(<queuename>)",
4226 .desc =
4227 "Returns the number of members currently associated with the specified queue.\n"
4228 "This function is deprecated. You should use QUEUE_MEMBER_COUNT() instead.\n",
4229 .read = queue_function_qac,
4232 static struct ast_custom_function queuemembercount_function = {
4233 .name = "QUEUE_MEMBER_COUNT",
4234 .synopsis = "Count number of members answering a queue",
4235 .syntax = "QUEUE_MEMBER_COUNT(<queuename>)",
4236 .desc =
4237 "Returns the number of members currently associated with the specified queue.\n",
4238 .read = queue_function_qac,
4241 static struct ast_custom_function queuewaitingcount_function = {
4242 .name = "QUEUE_WAITING_COUNT",
4243 .synopsis = "Count number of calls currently waiting in a queue",
4244 .syntax = "QUEUE_WAITING_COUNT(<queuename>)",
4245 .desc =
4246 "Returns the number of callers currently waiting in the specified queue.\n",
4247 .read = queue_function_queuewaitingcount,
4250 static struct ast_custom_function queuememberlist_function = {
4251 .name = "QUEUE_MEMBER_LIST",
4252 .synopsis = "Returns a list of interfaces on a queue",
4253 .syntax = "QUEUE_MEMBER_LIST(<queuename>)",
4254 .desc =
4255 "Returns a comma-separated list of members associated with the specified queue.\n",
4256 .read = queue_function_queuememberlist,
4259 static int reload_queues(void)
4261 struct call_queue *q;
4262 struct ast_config *cfg;
4263 char *cat, *tmp;
4264 struct ast_variable *var;
4265 struct member *cur, *newm;
4266 struct ao2_iterator mem_iter;
4267 int new;
4268 const char *general_val = NULL;
4269 char parse[80];
4270 char *interface;
4271 char *membername = NULL;
4272 int penalty;
4273 AST_DECLARE_APP_ARGS(args,
4274 AST_APP_ARG(interface);
4275 AST_APP_ARG(penalty);
4276 AST_APP_ARG(membername);
4279 if (!(cfg = ast_config_load("queues.conf"))) {
4280 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
4281 return 0;
4283 AST_LIST_LOCK(&queues);
4284 use_weight=0;
4285 /* Mark all non-realtime queues as dead for the moment */
4286 AST_LIST_TRAVERSE(&queues, q, list) {
4287 if (!q->realtime) {
4288 q->dead = 1;
4289 q->found = 0;
4293 /* Chug through config file */
4294 cat = NULL;
4295 while ((cat = ast_category_browse(cfg, cat)) ) {
4296 if (!strcasecmp(cat, "general")) {
4297 /* Initialize global settings */
4298 queue_persistent_members = 0;
4299 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
4300 queue_persistent_members = ast_true(general_val);
4301 autofill_default = 0;
4302 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill")))
4303 autofill_default = ast_true(general_val);
4304 montype_default = 0;
4305 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type")))
4306 if (!strcasecmp(general_val, "mixmonitor"))
4307 montype_default = 1;
4308 } else { /* Define queue */
4309 /* Look for an existing one */
4310 AST_LIST_TRAVERSE(&queues, q, list) {
4311 if (!strcmp(q->name, cat))
4312 break;
4314 if (!q) {
4315 /* Make one then */
4316 if (!(q = alloc_queue(cat))) {
4317 /* TODO: Handle memory allocation failure */
4319 new = 1;
4320 } else
4321 new = 0;
4322 if (q) {
4323 if (!new)
4324 ast_mutex_lock(&q->lock);
4325 /* Check if a queue with this name already exists */
4326 if (q->found) {
4327 ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", cat);
4328 if (!new)
4329 ast_mutex_unlock(&q->lock);
4330 continue;
4332 /* Re-initialize the queue, and clear statistics */
4333 init_queue(q);
4334 clear_queue(q);
4335 mem_iter = ao2_iterator_init(q->members, 0);
4336 while ((cur = ao2_iterator_next(&mem_iter))) {
4337 if (!cur->dynamic) {
4338 cur->delme = 1;
4340 ao2_ref(cur, -1);
4342 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
4343 if (!strcasecmp(var->name, "member")) {
4344 struct member tmpmem;
4345 membername = NULL;
4347 /* Add a new member */
4348 ast_copy_string(parse, var->value, sizeof(parse));
4350 AST_NONSTANDARD_APP_ARGS(args, parse, ',');
4352 interface = args.interface;
4353 if (!ast_strlen_zero(args.penalty)) {
4354 tmp = args.penalty;
4355 while (*tmp && *tmp < 33) tmp++;
4356 penalty = atoi(tmp);
4357 if (penalty < 0) {
4358 penalty = 0;
4360 } else
4361 penalty = 0;
4363 if (!ast_strlen_zero(args.membername)) {
4364 membername = args.membername;
4365 while (*membername && *membername < 33) membername++;
4368 /* Find the old position in the list */
4369 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
4370 cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK);
4372 newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0);
4373 ao2_link(q->members, newm);
4374 ao2_ref(newm, -1);
4375 newm = NULL;
4377 if (cur)
4378 ao2_ref(cur, -1);
4379 else {
4380 /* Add them to the master int list if necessary */
4381 add_to_interfaces(interface);
4382 q->membercount++;
4384 } else {
4385 queue_set_param(q, var->name, var->value, var->lineno, 1);
4389 /* Free remaining members marked as delme */
4390 mem_iter = ao2_iterator_init(q->members, 0);
4391 while ((cur = ao2_iterator_next(&mem_iter))) {
4392 if (! cur->delme) {
4393 ao2_ref(cur, -1);
4394 continue;
4397 q->membercount--;
4398 ao2_unlink(q->members, cur);
4399 remove_from_interfaces(cur->interface);
4400 ao2_ref(cur, -1);
4403 if (q->strategy == QUEUE_STRATEGY_ROUNDROBIN)
4404 rr_dep_warning();
4406 if (new) {
4407 AST_LIST_INSERT_HEAD(&queues, q, list);
4408 } else
4409 ast_mutex_unlock(&q->lock);
4413 ast_config_destroy(cfg);
4414 AST_LIST_TRAVERSE_SAFE_BEGIN(&queues, q, list) {
4415 if (q->dead) {
4416 AST_LIST_REMOVE_CURRENT(&queues, list);
4417 if (!q->count)
4418 destroy_queue(q);
4419 else
4420 ast_log(LOG_DEBUG, "XXX Leaking a little memory :( XXX\n");
4421 } else {
4422 ast_mutex_lock(&q->lock);
4423 mem_iter = ao2_iterator_init(q->members, 0);
4424 while ((cur = ao2_iterator_next(&mem_iter))) {
4425 if (cur->dynamic)
4426 q->membercount++;
4427 cur->status = ast_device_state(cur->interface);
4428 ao2_ref(cur, -1);
4430 ast_mutex_unlock(&q->lock);
4433 AST_LIST_TRAVERSE_SAFE_END;
4434 AST_LIST_UNLOCK(&queues);
4435 return 1;
4438 static int __queues_show(struct mansession *s, int manager, int fd, int argc, char **argv)
4440 struct call_queue *q;
4441 struct queue_ent *qe;
4442 struct member *mem;
4443 int pos, queue_show;
4444 time_t now;
4445 char max_buf[150];
4446 char *max;
4447 size_t max_left;
4448 float sl = 0;
4449 char *term = manager ? "\r\n" : "\n";
4450 struct ao2_iterator mem_iter;
4452 time(&now);
4453 if (argc == 2)
4454 queue_show = 0;
4455 else if (argc == 3)
4456 queue_show = 1;
4457 else
4458 return RESULT_SHOWUSAGE;
4460 /* We only want to load realtime queues when a specific queue is asked for. */
4461 if (queue_show) {
4462 load_realtime_queue(argv[2]);
4463 } else if (ast_check_realtime("queues")) {
4464 struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", (char *) NULL);
4465 char *queuename;
4466 if (cfg) {
4467 for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) {
4468 load_realtime_queue(queuename);
4470 ast_config_destroy(cfg);
4474 AST_LIST_LOCK(&queues);
4475 if (AST_LIST_EMPTY(&queues)) {
4476 AST_LIST_UNLOCK(&queues);
4477 if (queue_show) {
4478 if (s)
4479 astman_append(s, "No such queue: %s.%s",argv[2], term);
4480 else
4481 ast_cli(fd, "No such queue: %s.%s",argv[2], term);
4482 } else {
4483 if (s)
4484 astman_append(s, "No queues.%s", term);
4485 else
4486 ast_cli(fd, "No queues.%s", term);
4488 return RESULT_SUCCESS;
4490 AST_LIST_TRAVERSE(&queues, q, list) {
4491 ast_mutex_lock(&q->lock);
4492 if (queue_show) {
4493 if (strcasecmp(q->name, argv[2]) != 0) {
4494 ast_mutex_unlock(&q->lock);
4495 if (!AST_LIST_NEXT(q, list)) {
4496 ast_cli(fd, "No such queue: %s.%s",argv[2], term);
4497 break;
4499 continue;
4502 max_buf[0] = '\0';
4503 max = max_buf;
4504 max_left = sizeof(max_buf);
4505 if (q->maxlen)
4506 ast_build_string(&max, &max_left, "%d", q->maxlen);
4507 else
4508 ast_build_string(&max, &max_left, "unlimited");
4509 sl = 0;
4510 if (q->callscompleted > 0)
4511 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
4512 if (s)
4513 astman_append(s, "%-12.12s has %d calls (max %s) in '%s' strategy (%ds holdtime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds%s",
4514 q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->weight,
4515 q->callscompleted, q->callsabandoned,sl,q->servicelevel, term);
4516 else
4517 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%s",
4518 q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->weight, q->callscompleted, q->callsabandoned,sl,q->servicelevel, term);
4519 if (ao2_container_count(q->members)) {
4520 if (s)
4521 astman_append(s, " Members: %s", term);
4522 else
4523 ast_cli(fd, " Members: %s", term);
4524 mem_iter = ao2_iterator_init(q->members, 0);
4525 while ((mem = ao2_iterator_next(&mem_iter))) {
4526 max_buf[0] = '\0';
4527 max = max_buf;
4528 max_left = sizeof(max_buf);
4529 if (strcasecmp(mem->membername, mem->interface)) {
4530 ast_build_string(&max, &max_left, " (%s)", mem->interface);
4532 if (mem->penalty)
4533 ast_build_string(&max, &max_left, " with penalty %d", mem->penalty);
4534 if (mem->dynamic)
4535 ast_build_string(&max, &max_left, " (dynamic)");
4536 if (mem->realtime)
4537 ast_build_string(&max, &max_left, " (realtime)");
4538 if (mem->paused)
4539 ast_build_string(&max, &max_left, " (paused)");
4540 ast_build_string(&max, &max_left, " (%s)", devstate2str(mem->status));
4541 if (mem->calls) {
4542 ast_build_string(&max, &max_left, " has taken %d calls (last was %ld secs ago)",
4543 mem->calls, (long) (time(NULL) - mem->lastcall));
4544 } else
4545 ast_build_string(&max, &max_left, " has taken no calls yet");
4546 if (s)
4547 astman_append(s, " %s%s%s", mem->membername, max_buf, term);
4548 else
4549 ast_cli(fd, " %s%s%s", mem->membername, max_buf, term);
4550 ao2_ref(mem, -1);
4552 } else if (s)
4553 astman_append(s, " No Members%s", term);
4554 else
4555 ast_cli(fd, " No Members%s", term);
4556 if (q->head) {
4557 pos = 1;
4558 if (s)
4559 astman_append(s, " Callers: %s", term);
4560 else
4561 ast_cli(fd, " Callers: %s", term);
4562 for (qe = q->head; qe; qe = qe->next) {
4563 if (s)
4564 astman_append(s, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s",
4565 pos++, qe->chan->name, (long) (now - qe->start) / 60,
4566 (long) (now - qe->start) % 60, qe->prio, term);
4567 else
4568 ast_cli(fd, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s", pos++,
4569 qe->chan->name, (long) (now - qe->start) / 60,
4570 (long) (now - qe->start) % 60, qe->prio, term);
4572 } else if (s)
4573 astman_append(s, " No Callers%s", term);
4574 else
4575 ast_cli(fd, " No Callers%s", term);
4576 if (s)
4577 astman_append(s, "%s", term);
4578 else
4579 ast_cli(fd, "%s", term);
4580 ast_mutex_unlock(&q->lock);
4581 if (queue_show)
4582 break;
4584 AST_LIST_UNLOCK(&queues);
4585 return RESULT_SUCCESS;
4588 static int queue_show(int fd, int argc, char **argv)
4590 return __queues_show(NULL, 0, fd, argc, argv);
4593 static char *complete_queue(const char *line, const char *word, int pos, int state)
4595 struct call_queue *q;
4596 char *ret = NULL;
4597 int which = 0;
4598 int wordlen = strlen(word);
4600 AST_LIST_LOCK(&queues);
4601 AST_LIST_TRAVERSE(&queues, q, list) {
4602 if (!strncasecmp(word, q->name, wordlen) && ++which > state) {
4603 ret = ast_strdup(q->name);
4604 break;
4607 AST_LIST_UNLOCK(&queues);
4609 return ret;
4612 static char *complete_queue_show(const char *line, const char *word, int pos, int state)
4614 if (pos == 2)
4615 return complete_queue(line, word, pos, state);
4616 return NULL;
4619 /*!\brief callback to display queues status in manager
4620 \addtogroup Group_AMI
4622 static int manager_queues_show(struct mansession *s, const struct message *m)
4624 char *a[] = { "queue", "show" };
4626 __queues_show(s, 1, -1, 2, a);
4627 astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */
4629 return RESULT_SUCCESS;
4632 /* Dump queue status */
4633 static int manager_queues_status(struct mansession *s, const struct message *m)
4635 time_t now;
4636 int pos;
4637 const char *id = astman_get_header(m,"ActionID");
4638 const char *queuefilter = astman_get_header(m,"Queue");
4639 const char *memberfilter = astman_get_header(m,"Member");
4640 char idText[256] = "";
4641 struct call_queue *q;
4642 struct queue_ent *qe;
4643 float sl = 0;
4644 struct member *mem;
4645 struct ao2_iterator mem_iter;
4647 astman_send_ack(s, m, "Queue status will follow");
4648 time(&now);
4649 AST_LIST_LOCK(&queues);
4650 if (!ast_strlen_zero(id))
4651 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
4653 AST_LIST_TRAVERSE(&queues, q, list) {
4654 ast_mutex_lock(&q->lock);
4656 /* List queue properties */
4657 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
4658 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0);
4659 astman_append(s, "Event: QueueParams\r\n"
4660 "Queue: %s\r\n"
4661 "Max: %d\r\n"
4662 "Calls: %d\r\n"
4663 "Holdtime: %d\r\n"
4664 "Completed: %d\r\n"
4665 "Abandoned: %d\r\n"
4666 "ServiceLevel: %d\r\n"
4667 "ServicelevelPerf: %2.1f\r\n"
4668 "Weight: %d\r\n"
4669 "%s"
4670 "\r\n",
4671 q->name, q->maxlen, q->count, q->holdtime, q->callscompleted,
4672 q->callsabandoned, q->servicelevel, sl, q->weight, idText);
4673 /* List Queue Members */
4674 mem_iter = ao2_iterator_init(q->members, 0);
4675 while ((mem = ao2_iterator_next(&mem_iter))) {
4676 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter)) {
4677 astman_append(s, "Event: QueueMember\r\n"
4678 "Queue: %s\r\n"
4679 "Name: %s\r\n"
4680 "Location: %s\r\n"
4681 "Membership: %s\r\n"
4682 "Penalty: %d\r\n"
4683 "CallsTaken: %d\r\n"
4684 "LastCall: %d\r\n"
4685 "Status: %d\r\n"
4686 "Paused: %d\r\n"
4687 "%s"
4688 "\r\n",
4689 q->name, mem->membername, mem->interface, mem->dynamic ? "dynamic" : "static",
4690 mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText);
4692 ao2_ref(mem, -1);
4694 /* List Queue Entries */
4695 pos = 1;
4696 for (qe = q->head; qe; qe = qe->next) {
4697 astman_append(s, "Event: QueueEntry\r\n"
4698 "Queue: %s\r\n"
4699 "Position: %d\r\n"
4700 "Channel: %s\r\n"
4701 "CallerID: %s\r\n"
4702 "CallerIDName: %s\r\n"
4703 "Wait: %ld\r\n"
4704 "%s"
4705 "\r\n",
4706 q->name, pos++, qe->chan->name,
4707 S_OR(qe->chan->cid.cid_num, "unknown"),
4708 S_OR(qe->chan->cid.cid_name, "unknown"),
4709 (long) (now - qe->start), idText);
4712 ast_mutex_unlock(&q->lock);
4715 astman_append(s,
4716 "Event: QueueStatusComplete\r\n"
4717 "%s"
4718 "\r\n",idText);
4720 AST_LIST_UNLOCK(&queues);
4723 return RESULT_SUCCESS;
4726 static int manager_add_queue_member(struct mansession *s, const struct message *m)
4728 const char *queuename, *interface, *penalty_s, *paused_s, *membername;
4729 int paused, penalty = 0;
4731 queuename = astman_get_header(m, "Queue");
4732 interface = astman_get_header(m, "Interface");
4733 penalty_s = astman_get_header(m, "Penalty");
4734 paused_s = astman_get_header(m, "Paused");
4735 membername = astman_get_header(m, "MemberName");
4737 if (ast_strlen_zero(queuename)) {
4738 astman_send_error(s, m, "'Queue' not specified.");
4739 return 0;
4742 if (ast_strlen_zero(interface)) {
4743 astman_send_error(s, m, "'Interface' not specified.");
4744 return 0;
4747 if (ast_strlen_zero(penalty_s))
4748 penalty = 0;
4749 else if (sscanf(penalty_s, "%d", &penalty) != 1 || penalty < 0)
4750 penalty = 0;
4752 if (ast_strlen_zero(paused_s))
4753 paused = 0;
4754 else
4755 paused = abs(ast_true(paused_s));
4757 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members)) {
4758 case RES_OKAY:
4759 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", "");
4760 astman_send_ack(s, m, "Added interface to queue");
4761 break;
4762 case RES_EXISTS:
4763 astman_send_error(s, m, "Unable to add interface: Already there");
4764 break;
4765 case RES_NOSUCHQUEUE:
4766 astman_send_error(s, m, "Unable to add interface to queue: No such queue");
4767 break;
4768 case RES_OUTOFMEMORY:
4769 astman_send_error(s, m, "Out of memory");
4770 break;
4773 return 0;
4776 static int manager_remove_queue_member(struct mansession *s, const struct message *m)
4778 const char *queuename, *interface;
4780 queuename = astman_get_header(m, "Queue");
4781 interface = astman_get_header(m, "Interface");
4783 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
4784 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
4785 return 0;
4788 switch (remove_from_queue(queuename, interface)) {
4789 case RES_OKAY:
4790 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
4791 astman_send_ack(s, m, "Removed interface from queue");
4792 break;
4793 case RES_EXISTS:
4794 astman_send_error(s, m, "Unable to remove interface: Not there");
4795 break;
4796 case RES_NOSUCHQUEUE:
4797 astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
4798 break;
4799 case RES_OUTOFMEMORY:
4800 astman_send_error(s, m, "Out of memory");
4801 break;
4802 case RES_NOT_DYNAMIC:
4803 astman_send_error(s, m, "Member not dynamic");
4804 break;
4807 return 0;
4810 static int manager_pause_queue_member(struct mansession *s, const struct message *m)
4812 const char *queuename, *interface, *paused_s;
4813 int paused;
4815 interface = astman_get_header(m, "Interface");
4816 paused_s = astman_get_header(m, "Paused");
4817 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */
4819 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
4820 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
4821 return 0;
4824 paused = abs(ast_true(paused_s));
4826 if (set_member_paused(queuename, interface, paused))
4827 astman_send_error(s, m, "Interface not found");
4828 else
4829 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
4830 return 0;
4833 static int handle_queue_add_member(int fd, int argc, char *argv[])
4835 char *queuename, *interface, *membername = NULL;
4836 int penalty;
4838 if ((argc != 6) && (argc != 8) && (argc != 10)) {
4839 return RESULT_SHOWUSAGE;
4840 } else if (strcmp(argv[4], "to")) {
4841 return RESULT_SHOWUSAGE;
4842 } else if ((argc == 8) && strcmp(argv[6], "penalty")) {
4843 return RESULT_SHOWUSAGE;
4844 } else if ((argc == 10) && strcmp(argv[8], "as")) {
4845 return RESULT_SHOWUSAGE;
4848 queuename = argv[5];
4849 interface = argv[3];
4850 if (argc >= 8) {
4851 if (sscanf(argv[7], "%d", &penalty) == 1) {
4852 if (penalty < 0) {
4853 ast_cli(fd, "Penalty must be >= 0\n");
4854 penalty = 0;
4856 } else {
4857 ast_cli(fd, "Penalty must be an integer >= 0\n");
4858 penalty = 0;
4860 } else {
4861 penalty = 0;
4864 if (argc >= 10) {
4865 membername = argv[9];
4868 switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members)) {
4869 case RES_OKAY:
4870 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
4871 ast_cli(fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
4872 return RESULT_SUCCESS;
4873 case RES_EXISTS:
4874 ast_cli(fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
4875 return RESULT_FAILURE;
4876 case RES_NOSUCHQUEUE:
4877 ast_cli(fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
4878 return RESULT_FAILURE;
4879 case RES_OUTOFMEMORY:
4880 ast_cli(fd, "Out of memory\n");
4881 return RESULT_FAILURE;
4882 default:
4883 return RESULT_FAILURE;
4887 static char *complete_queue_add_member(const char *line, const char *word, int pos, int state)
4889 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
4890 switch (pos) {
4891 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
4892 return NULL;
4893 case 4: /* only one possible match, "to" */
4894 return state == 0 ? ast_strdup("to") : NULL;
4895 case 5: /* <queue> */
4896 return complete_queue(line, word, pos, state);
4897 case 6: /* only one possible match, "penalty" */
4898 return state == 0 ? ast_strdup("penalty") : NULL;
4899 case 7:
4900 if (state < 100) { /* 0-99 */
4901 char *num;
4902 if ((num = ast_malloc(3))) {
4903 sprintf(num, "%d", state);
4905 return num;
4906 } else {
4907 return NULL;
4909 case 8: /* only one possible match, "as" */
4910 return state == 0 ? ast_strdup("as") : NULL;
4911 case 9: /* Don't attempt to complete name of member (infinite possibilities) */
4912 return NULL;
4913 default:
4914 return NULL;
4918 static int handle_queue_remove_member(int fd, int argc, char *argv[])
4920 char *queuename, *interface;
4922 if (argc != 6) {
4923 return RESULT_SHOWUSAGE;
4924 } else if (strcmp(argv[4], "from")) {
4925 return RESULT_SHOWUSAGE;
4928 queuename = argv[5];
4929 interface = argv[3];
4931 switch (remove_from_queue(queuename, interface)) {
4932 case RES_OKAY:
4933 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
4934 ast_cli(fd, "Removed interface '%s' from queue '%s'\n", interface, queuename);
4935 return RESULT_SUCCESS;
4936 case RES_EXISTS:
4937 ast_cli(fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
4938 return RESULT_FAILURE;
4939 case RES_NOSUCHQUEUE:
4940 ast_cli(fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
4941 return RESULT_FAILURE;
4942 case RES_OUTOFMEMORY:
4943 ast_cli(fd, "Out of memory\n");
4944 return RESULT_FAILURE;
4945 case RES_NOT_DYNAMIC:
4946 ast_cli(fd, "Member not dynamic\n");
4947 return RESULT_FAILURE;
4948 default:
4949 return RESULT_FAILURE;
4953 static char *complete_queue_remove_member(const char *line, const char *word, int pos, int state)
4955 int which = 0;
4956 struct call_queue *q;
4957 struct member *m;
4958 struct ao2_iterator mem_iter;
4960 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
4961 if (pos > 5 || pos < 3)
4962 return NULL;
4963 if (pos == 4) /* only one possible match, 'from' */
4964 return state == 0 ? ast_strdup("from") : NULL;
4966 if (pos == 5) /* No need to duplicate code */
4967 return complete_queue(line, word, pos, state);
4969 /* here is the case for 3, <member> */
4970 if (!AST_LIST_EMPTY(&queues)) { /* XXX unnecessary ? the traverse does that for us */
4971 AST_LIST_TRAVERSE(&queues, q, list) {
4972 ast_mutex_lock(&q->lock);
4973 mem_iter = ao2_iterator_init(q->members, 0);
4974 while ((m = ao2_iterator_next(&mem_iter))) {
4975 if (++which > state) {
4976 char *tmp;
4977 ast_mutex_unlock(&q->lock);
4978 tmp = ast_strdup(m->interface);
4979 ao2_ref(m, -1);
4980 return tmp;
4982 ao2_ref(m, -1);
4984 ast_mutex_unlock(&q->lock);
4988 return NULL;
4991 static char queue_show_usage[] =
4992 "Usage: queue show\n"
4993 " Provides summary information on a specified queue.\n";
4995 static char qam_cmd_usage[] =
4996 "Usage: queue add member <channel> to <queue> [penalty <penalty>]\n";
4998 static char qrm_cmd_usage[] =
4999 "Usage: queue remove member <channel> from <queue>\n";
5001 static struct ast_cli_entry cli_show_queue_deprecated = {
5002 { "show", "queue", NULL },
5003 queue_show, NULL,
5004 NULL, complete_queue_show };
5006 static struct ast_cli_entry cli_add_queue_member_deprecated = {
5007 { "add", "queue", "member", NULL },
5008 handle_queue_add_member, NULL,
5009 NULL, complete_queue_add_member };
5011 static struct ast_cli_entry cli_remove_queue_member_deprecated = {
5012 { "remove", "queue", "member", NULL },
5013 handle_queue_remove_member, NULL,
5014 NULL, complete_queue_remove_member };
5016 static struct ast_cli_entry cli_queue[] = {
5017 /* Deprecated */
5018 { { "show", "queues", NULL },
5019 queue_show, NULL,
5020 NULL, NULL },
5022 { { "queue", "show", NULL },
5023 queue_show, "Show status of a specified queue",
5024 queue_show_usage, complete_queue_show, &cli_show_queue_deprecated },
5026 { { "queue", "add", "member", NULL },
5027 handle_queue_add_member, "Add a channel to a specified queue",
5028 qam_cmd_usage, complete_queue_add_member, &cli_add_queue_member_deprecated },
5030 { { "queue", "remove", "member", NULL },
5031 handle_queue_remove_member, "Removes a channel from a specified queue",
5032 qrm_cmd_usage, complete_queue_remove_member, &cli_remove_queue_member_deprecated },
5035 static int unload_module(void)
5037 int res;
5039 if (device_state.thread != AST_PTHREADT_NULL) {
5040 device_state.stop = 1;
5041 ast_mutex_lock(&device_state.lock);
5042 ast_cond_signal(&device_state.cond);
5043 ast_mutex_unlock(&device_state.lock);
5044 pthread_join(device_state.thread, NULL);
5047 ast_cli_unregister_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry));
5048 res = ast_manager_unregister("QueueStatus");
5049 res |= ast_manager_unregister("Queues");
5050 res |= ast_manager_unregister("QueueAdd");
5051 res |= ast_manager_unregister("QueueRemove");
5052 res |= ast_manager_unregister("QueuePause");
5053 res |= ast_unregister_application(app_aqm);
5054 res |= ast_unregister_application(app_rqm);
5055 res |= ast_unregister_application(app_pqm);
5056 res |= ast_unregister_application(app_upqm);
5057 res |= ast_unregister_application(app_ql);
5058 res |= ast_unregister_application(app);
5059 res |= ast_custom_function_unregister(&queueagentcount_function);
5060 res |= ast_custom_function_unregister(&queuemembercount_function);
5061 res |= ast_custom_function_unregister(&queuememberlist_function);
5062 res |= ast_custom_function_unregister(&queuewaitingcount_function);
5063 ast_devstate_del(statechange_queue, NULL);
5065 ast_module_user_hangup_all();
5067 clear_and_free_interfaces();
5069 return res;
5072 static int load_module(void)
5074 int res;
5076 if (!reload_queues())
5077 return AST_MODULE_LOAD_DECLINE;
5079 if (queue_persistent_members)
5080 reload_queue_members();
5082 ast_mutex_init(&device_state.lock);
5083 ast_cond_init(&device_state.cond, NULL);
5084 ast_pthread_create(&device_state.thread, NULL, device_state_thread, NULL);
5086 ast_cli_register_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry));
5087 res = ast_register_application(app, queue_exec, synopsis, descrip);
5088 res |= ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip);
5089 res |= ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip);
5090 res |= ast_register_application(app_pqm, pqm_exec, app_pqm_synopsis, app_pqm_descrip);
5091 res |= ast_register_application(app_upqm, upqm_exec, app_upqm_synopsis, app_upqm_descrip);
5092 res |= ast_register_application(app_ql, ql_exec, app_ql_synopsis, app_ql_descrip);
5093 res |= ast_manager_register("Queues", 0, manager_queues_show, "Queues");
5094 res |= ast_manager_register("QueueStatus", 0, manager_queues_status, "Queue Status");
5095 res |= ast_manager_register("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member, "Add interface to queue.");
5096 res |= ast_manager_register("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member, "Remove interface from queue.");
5097 res |= ast_manager_register("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member, "Makes a queue member temporarily unavailable");
5098 res |= ast_custom_function_register(&queueagentcount_function);
5099 res |= ast_custom_function_register(&queuemembercount_function);
5100 res |= ast_custom_function_register(&queuememberlist_function);
5101 res |= ast_custom_function_register(&queuewaitingcount_function);
5102 res |= ast_devstate_add(statechange_queue, NULL);
5104 return res;
5107 static int reload(void)
5109 reload_queues();
5110 return 0;
5113 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "True Call Queueing",
5114 .load = load_module,
5115 .unload = unload_module,
5116 .reload = reload,