Merge changes from team/russell/issue_9520
[asterisk-bristuff.git] / apps / app_queue.c
blob08e85c02fbd08b39bfe5f91b63f1768b099ce314
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 recursive boxcar filter */
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 rr_dep_warning(void)
446 static unsigned int warned = 0;
448 if (!warned) {
449 ast_log(LOG_NOTICE, "The 'roundrobin' queue strategy is deprecated. Please use the 'rrmemory' strategy instead.\n");
450 warned = 1;
454 static void monjoin_dep_warning(void)
456 static unsigned int warned = 0;
457 if (!warned) {
458 ast_log(LOG_NOTICE, "The 'monitor-join' queue option is deprecated. Please use monitor-type=mixmonitor instead.\n");
459 warned = 1;
462 /*! \brief sets the QUEUESTATUS channel variable */
463 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
465 int i;
467 for (i = 0; i < sizeof(queue_results) / sizeof(queue_results[0]); i++) {
468 if (queue_results[i].id == res) {
469 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
470 return;
475 static char *int2strat(int strategy)
477 int x;
479 for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) {
480 if (strategy == strategies[x].strategy)
481 return strategies[x].name;
484 return "<unknown>";
487 static int strat2int(const char *strategy)
489 int x;
491 for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) {
492 if (!strcasecmp(strategy, strategies[x].name))
493 return strategies[x].strategy;
496 return -1;
499 /*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
500 static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
502 struct queue_ent *cur;
504 if (!q || !new)
505 return;
506 if (prev) {
507 cur = prev->next;
508 prev->next = new;
509 } else {
510 cur = q->head;
511 q->head = new;
513 new->next = cur;
514 new->parent = q;
515 new->pos = ++(*pos);
516 new->opos = *pos;
519 enum queue_member_status {
520 QUEUE_NO_MEMBERS,
521 QUEUE_NO_REACHABLE_MEMBERS,
522 QUEUE_NORMAL
525 /*! \brief Check if members are available
527 * This function checks to see if members are available to be called. If any member
528 * is available, the function immediately returns QUEUE_NORMAL. If no members are available,
529 * the appropriate reason why is returned
531 static enum queue_member_status get_member_status(struct call_queue *q, int max_penalty)
533 struct member *member;
534 struct ao2_iterator mem_iter;
535 enum queue_member_status result = QUEUE_NO_MEMBERS;
537 ast_mutex_lock(&q->lock);
538 mem_iter = ao2_iterator_init(q->members, 0);
539 while ((member = ao2_iterator_next(&mem_iter))) {
540 if (max_penalty && (member->penalty > max_penalty)) {
541 ao2_ref(member, -1);
542 continue;
545 if (member->paused) {
546 ao2_ref(member, -1);
547 continue;
550 switch (member->status) {
551 case AST_DEVICE_INVALID:
552 /* nothing to do */
553 ao2_ref(member, -1);
554 break;
555 case AST_DEVICE_UNAVAILABLE:
556 result = QUEUE_NO_REACHABLE_MEMBERS;
557 ao2_ref(member, -1);
558 break;
559 default:
560 ast_mutex_unlock(&q->lock);
561 ao2_ref(member, -1);
562 return QUEUE_NORMAL;
566 ast_mutex_unlock(&q->lock);
567 return result;
570 struct statechange {
571 AST_LIST_ENTRY(statechange) entry;
572 int state;
573 char dev[0];
576 static int update_status(const char *interface, const int status)
578 struct member *cur;
579 struct ao2_iterator mem_iter;
580 struct call_queue *q;
582 AST_LIST_LOCK(&queues);
583 AST_LIST_TRAVERSE(&queues, q, list) {
584 ast_mutex_lock(&q->lock);
585 mem_iter = ao2_iterator_init(q->members, 0);
586 while ((cur = ao2_iterator_next(&mem_iter))) {
587 char *tmp_interface;
588 char *slash_pos;
589 tmp_interface = ast_strdupa(cur->interface);
590 if ((slash_pos = strchr(tmp_interface, '/')))
591 if ((slash_pos = strchr(slash_pos + 1, '/')))
592 *slash_pos = '\0';
594 if (strcasecmp(interface, tmp_interface)) {
595 ao2_ref(cur, -1);
596 continue;
599 if (cur->status != status) {
600 cur->status = status;
601 if (q->maskmemberstatus) {
602 ao2_ref(cur, -1);
603 continue;
606 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
607 "Queue: %s\r\n"
608 "Location: %s\r\n"
609 "MemberName: %s\r\n"
610 "Membership: %s\r\n"
611 "Penalty: %d\r\n"
612 "CallsTaken: %d\r\n"
613 "LastCall: %d\r\n"
614 "Status: %d\r\n"
615 "Paused: %d\r\n",
616 q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : cur->realtime ? "realtime" : "static",
617 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
619 ao2_ref(cur, -1);
621 ast_mutex_unlock(&q->lock);
623 AST_LIST_UNLOCK(&queues);
625 return 0;
628 /*! \brief set a member's status based on device state of that member's interface*/
629 static void *handle_statechange(struct statechange *sc)
631 struct member_interface *curint;
632 char *loc;
633 char *technology;
635 technology = ast_strdupa(sc->dev);
636 loc = strchr(technology, '/');
637 if (loc) {
638 *loc++ = '\0';
639 } else {
640 return NULL;
643 AST_LIST_LOCK(&interfaces);
644 AST_LIST_TRAVERSE(&interfaces, curint, list) {
645 char *interface;
646 char *slash_pos;
647 interface = ast_strdupa(curint->interface);
648 if ((slash_pos = strchr(interface, '/')))
649 if ((slash_pos = strchr(slash_pos + 1, '/')))
650 *slash_pos = '\0';
652 if (!strcasecmp(interface, sc->dev))
653 break;
655 AST_LIST_UNLOCK(&interfaces);
657 if (!curint) {
658 if (option_debug > 2)
659 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));
660 return NULL;
663 if (option_debug)
664 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state));
666 update_status(sc->dev, sc->state);
668 return NULL;
672 * \brief Data used by the device state thread
674 static struct {
675 /*! Set to 1 to stop the thread */
676 unsigned int stop:1;
677 /*! The device state monitoring thread */
678 pthread_t thread;
679 /*! Lock for the state change queue */
680 ast_mutex_t lock;
681 /*! Condition for the state change queue */
682 ast_cond_t cond;
683 /*! Queue of state changes */
684 AST_LIST_HEAD_NOLOCK(, statechange) state_change_q;
685 } device_state = {
686 .thread = AST_PTHREADT_NULL,
689 /*! \brief Consumer of the statechange queue */
690 static void *device_state_thread(void *data)
692 struct statechange *sc = NULL;
694 while (!device_state.stop) {
695 ast_mutex_lock(&device_state.lock);
696 if (!(sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry))) {
697 ast_cond_wait(&device_state.cond, &device_state.lock);
698 sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry);
700 ast_mutex_unlock(&device_state.lock);
702 /* Check to see if we were woken up to see the request to stop */
703 if (device_state.stop)
704 break;
706 if (!sc)
707 continue;
709 handle_statechange(sc);
711 free(sc);
712 sc = NULL;
715 if (sc)
716 free(sc);
718 while ((sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry)))
719 free(sc);
721 return NULL;
723 /*! \brief Producer of the statechange queue */
724 static int statechange_queue(const char *dev, int state, void *ign)
726 struct statechange *sc;
728 if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(dev) + 1)))
729 return 0;
731 sc->state = state;
732 strcpy(sc->dev, dev);
734 ast_mutex_lock(&device_state.lock);
735 AST_LIST_INSERT_TAIL(&device_state.state_change_q, sc, entry);
736 ast_cond_signal(&device_state.cond);
737 ast_mutex_unlock(&device_state.lock);
739 return 0;
741 /*! \brief allocate space for new queue member and set fields based on parameters passed */
742 static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused)
744 struct member *cur;
746 if ((cur = ao2_alloc(sizeof(*cur), NULL))) {
747 cur->penalty = penalty;
748 cur->paused = paused;
749 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
750 if (!ast_strlen_zero(membername))
751 ast_copy_string(cur->membername, membername, sizeof(cur->membername));
752 else
753 ast_copy_string(cur->membername, interface, sizeof(cur->membername));
754 if (!strchr(cur->interface, '/'))
755 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
756 cur->status = ast_device_state(interface);
759 return cur;
762 static struct call_queue *alloc_queue(const char *queuename)
764 struct call_queue *q;
766 if ((q = ast_calloc(1, sizeof(*q)))) {
767 ast_mutex_init(&q->lock);
768 ast_copy_string(q->name, queuename, sizeof(q->name));
770 return q;
773 static int compress_char(const char c)
775 if (c < 32)
776 return 0;
777 else if (c > 96)
778 return c - 64;
779 else
780 return c - 32;
783 static int member_hash_fn(const void *obj, const int flags)
785 const struct member *mem = obj;
786 const char *chname = strchr(mem->interface, '/');
787 int ret = 0, i;
788 if (!chname)
789 chname = mem->interface;
790 for (i = 0; i < 5 && chname[i]; i++)
791 ret += compress_char(chname[i]) << (i * 6);
792 return ret;
795 static int member_cmp_fn(void *obj1, void *obj2, int flags)
797 struct member *mem1 = obj1, *mem2 = obj2;
798 return strcmp(mem1->interface, mem2->interface) ? 0 : CMP_MATCH;
801 static void init_queue(struct call_queue *q)
803 int i;
805 q->dead = 0;
806 q->retry = DEFAULT_RETRY;
807 q->timeout = -1;
808 q->maxlen = 0;
809 q->announcefrequency = 0;
810 q->announceholdtime = 0;
811 q->roundingseconds = 0; /* Default - don't announce seconds */
812 q->servicelevel = 0;
813 q->ringinuse = 1;
814 q->setinterfacevar = 0;
815 q->autofill = autofill_default;
816 q->montype = montype_default;
817 q->moh[0] = '\0';
818 q->announce[0] = '\0';
819 q->context[0] = '\0';
820 q->monfmt[0] = '\0';
821 q->periodicannouncefrequency = 0;
822 q->reportholdtime = 0;
823 q->monjoin = 0;
824 q->wrapuptime = 0;
825 q->joinempty = 0;
826 q->leavewhenempty = 0;
827 q->memberdelay = 0;
828 q->maskmemberstatus = 0;
829 q->eventwhencalled = 0;
830 q->weight = 0;
831 q->timeoutrestart = 0;
832 if (!q->members)
833 q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
834 q->membercount = 0;
835 q->found = 1;
836 ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next));
837 ast_copy_string(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare));
838 ast_copy_string(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls));
839 ast_copy_string(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime));
840 ast_copy_string(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes));
841 ast_copy_string(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds));
842 ast_copy_string(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks));
843 ast_copy_string(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan));
844 ast_copy_string(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold));
845 ast_copy_string(q->sound_periodicannounce[0], "queue-periodic-announce", sizeof(q->sound_periodicannounce[0]));
846 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
847 q->sound_periodicannounce[i][0]='\0';
851 static void clear_queue(struct call_queue *q)
853 q->holdtime = 0;
854 q->callscompleted = 0;
855 q->callsabandoned = 0;
856 q->callscompletedinsl = 0;
857 q->wrapuptime = 0;
860 static int add_to_interfaces(const char *interface)
862 struct member_interface *curint;
864 AST_LIST_LOCK(&interfaces);
865 AST_LIST_TRAVERSE(&interfaces, curint, list) {
866 if (!strcasecmp(curint->interface, interface))
867 break;
870 if (curint) {
871 AST_LIST_UNLOCK(&interfaces);
872 return 0;
875 if (option_debug)
876 ast_log(LOG_DEBUG, "Adding %s to the list of interfaces that make up all of our queue members.\n", interface);
878 if ((curint = ast_calloc(1, sizeof(*curint)))) {
879 ast_copy_string(curint->interface, interface, sizeof(curint->interface));
880 AST_LIST_INSERT_HEAD(&interfaces, curint, list);
882 AST_LIST_UNLOCK(&interfaces);
884 return 0;
887 static int interface_exists_global(const char *interface)
889 struct call_queue *q;
890 struct member *mem, tmpmem;
891 int ret = 0;
893 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
895 AST_LIST_LOCK(&queues);
896 AST_LIST_TRAVERSE(&queues, q, list) {
897 ast_mutex_lock(&q->lock);
898 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
899 ao2_ref(mem, -1);
900 ret = 1;
902 ast_mutex_unlock(&q->lock);
903 if (ret)
904 break;
906 AST_LIST_UNLOCK(&queues);
908 return ret;
911 static int remove_from_interfaces(const char *interface)
913 struct member_interface *curint;
915 if (interface_exists_global(interface))
916 return 0;
918 AST_LIST_LOCK(&interfaces);
919 AST_LIST_TRAVERSE_SAFE_BEGIN(&interfaces, curint, list) {
920 if (!strcasecmp(curint->interface, interface)) {
921 if (option_debug)
922 ast_log(LOG_DEBUG, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface);
923 AST_LIST_REMOVE_CURRENT(&interfaces, list);
924 free(curint);
925 break;
928 AST_LIST_TRAVERSE_SAFE_END;
929 AST_LIST_UNLOCK(&interfaces);
931 return 0;
934 static void clear_and_free_interfaces(void)
936 struct member_interface *curint;
938 AST_LIST_LOCK(&interfaces);
939 while ((curint = AST_LIST_REMOVE_HEAD(&interfaces, list)))
940 free(curint);
941 AST_LIST_UNLOCK(&interfaces);
944 /*! \brief Configure a queue parameter.
945 \par
946 For error reporting, line number is passed for .conf static configuration.
947 For Realtime queues, linenum is -1.
948 The failunknown flag is set for config files (and static realtime) to show
949 errors for unknown parameters. It is cleared for dynamic realtime to allow
950 extra fields in the tables. */
951 static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
953 if (!strcasecmp(param, "musicclass") ||
954 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
955 ast_copy_string(q->moh, val, sizeof(q->moh));
956 } else if (!strcasecmp(param, "announce")) {
957 ast_copy_string(q->announce, val, sizeof(q->announce));
958 } else if (!strcasecmp(param, "context")) {
959 ast_copy_string(q->context, val, sizeof(q->context));
960 } else if (!strcasecmp(param, "timeout")) {
961 q->timeout = atoi(val);
962 if (q->timeout < 0)
963 q->timeout = DEFAULT_TIMEOUT;
964 } else if (!strcasecmp(param, "ringinuse")) {
965 q->ringinuse = ast_true(val);
966 } else if (!strcasecmp(param, "setinterfacevar")) {
967 q->setinterfacevar = ast_true(val);
968 } else if (!strcasecmp(param, "monitor-join")) {
969 monjoin_dep_warning();
970 q->monjoin = ast_true(val);
971 } else if (!strcasecmp(param, "monitor-format")) {
972 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
973 } else if (!strcasecmp(param, "queue-youarenext")) {
974 ast_copy_string(q->sound_next, val, sizeof(q->sound_next));
975 } else if (!strcasecmp(param, "queue-thereare")) {
976 ast_copy_string(q->sound_thereare, val, sizeof(q->sound_thereare));
977 } else if (!strcasecmp(param, "queue-callswaiting")) {
978 ast_copy_string(q->sound_calls, val, sizeof(q->sound_calls));
979 } else if (!strcasecmp(param, "queue-holdtime")) {
980 ast_copy_string(q->sound_holdtime, val, sizeof(q->sound_holdtime));
981 } else if (!strcasecmp(param, "queue-minutes")) {
982 ast_copy_string(q->sound_minutes, val, sizeof(q->sound_minutes));
983 } else if (!strcasecmp(param, "queue-seconds")) {
984 ast_copy_string(q->sound_seconds, val, sizeof(q->sound_seconds));
985 } else if (!strcasecmp(param, "queue-lessthan")) {
986 ast_copy_string(q->sound_lessthan, val, sizeof(q->sound_lessthan));
987 } else if (!strcasecmp(param, "queue-thankyou")) {
988 ast_copy_string(q->sound_thanks, val, sizeof(q->sound_thanks));
989 } else if (!strcasecmp(param, "queue-reporthold")) {
990 ast_copy_string(q->sound_reporthold, val, sizeof(q->sound_reporthold));
991 } else if (!strcasecmp(param, "announce-frequency")) {
992 q->announcefrequency = atoi(val);
993 } else if (!strcasecmp(param, "announce-round-seconds")) {
994 q->roundingseconds = atoi(val);
995 if (q->roundingseconds>60 || q->roundingseconds<0) {
996 if (linenum >= 0) {
997 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
998 "using 0 instead for queue '%s' at line %d of queues.conf\n",
999 val, param, q->name, linenum);
1000 } else {
1001 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
1002 "using 0 instead for queue '%s'\n", val, param, q->name);
1004 q->roundingseconds=0;
1006 } else if (!strcasecmp(param, "announce-holdtime")) {
1007 if (!strcasecmp(val, "once"))
1008 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
1009 else if (ast_true(val))
1010 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
1011 else
1012 q->announceholdtime = 0;
1013 } else if (!strcasecmp(param, "periodic-announce")) {
1014 if (strchr(val, '|')) {
1015 char *s, *buf = ast_strdupa(val);
1016 unsigned int i = 0;
1018 while ((s = strsep(&buf, "|"))) {
1019 ast_copy_string(q->sound_periodicannounce[i], s, sizeof(q->sound_periodicannounce[i]));
1020 i++;
1021 if (i == MAX_PERIODIC_ANNOUNCEMENTS)
1022 break;
1024 } else {
1025 ast_copy_string(q->sound_periodicannounce[0], val, sizeof(q->sound_periodicannounce[0]));
1027 } else if (!strcasecmp(param, "periodic-announce-frequency")) {
1028 q->periodicannouncefrequency = atoi(val);
1029 } else if (!strcasecmp(param, "retry")) {
1030 q->retry = atoi(val);
1031 if (q->retry <= 0)
1032 q->retry = DEFAULT_RETRY;
1033 } else if (!strcasecmp(param, "wrapuptime")) {
1034 q->wrapuptime = atoi(val);
1035 } else if (!strcasecmp(param, "autofill")) {
1036 q->autofill = ast_true(val);
1037 } else if (!strcasecmp(param, "monitor-type")) {
1038 if (!strcasecmp(val, "mixmonitor"))
1039 q->montype = 1;
1040 } else if (!strcasecmp(param, "autopause")) {
1041 q->autopause = ast_true(val);
1042 } else if (!strcasecmp(param, "maxlen")) {
1043 q->maxlen = atoi(val);
1044 if (q->maxlen < 0)
1045 q->maxlen = 0;
1046 } else if (!strcasecmp(param, "servicelevel")) {
1047 q->servicelevel= atoi(val);
1048 } else if (!strcasecmp(param, "strategy")) {
1049 q->strategy = strat2int(val);
1050 if (q->strategy < 0) {
1051 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
1052 val, q->name);
1053 q->strategy = QUEUE_STRATEGY_RINGALL;
1055 } else if (!strcasecmp(param, "joinempty")) {
1056 if (!strcasecmp(val, "strict"))
1057 q->joinempty = QUEUE_EMPTY_STRICT;
1058 else if (ast_true(val))
1059 q->joinempty = QUEUE_EMPTY_NORMAL;
1060 else
1061 q->joinempty = 0;
1062 } else if (!strcasecmp(param, "leavewhenempty")) {
1063 if (!strcasecmp(val, "strict"))
1064 q->leavewhenempty = QUEUE_EMPTY_STRICT;
1065 else if (ast_true(val))
1066 q->leavewhenempty = QUEUE_EMPTY_NORMAL;
1067 else
1068 q->leavewhenempty = 0;
1069 } else if (!strcasecmp(param, "eventmemberstatus")) {
1070 q->maskmemberstatus = !ast_true(val);
1071 } else if (!strcasecmp(param, "eventwhencalled")) {
1072 if (!strcasecmp(val, "vars")) {
1073 q->eventwhencalled = QUEUE_EVENT_VARIABLES;
1074 } else {
1075 q->eventwhencalled = ast_true(val) ? 1 : 0;
1077 } else if (!strcasecmp(param, "reportholdtime")) {
1078 q->reportholdtime = ast_true(val);
1079 } else if (!strcasecmp(param, "memberdelay")) {
1080 q->memberdelay = atoi(val);
1081 } else if (!strcasecmp(param, "weight")) {
1082 q->weight = atoi(val);
1083 if (q->weight)
1084 use_weight++;
1085 /* With Realtime queues, if the last queue using weights is deleted in realtime,
1086 we will not see any effect on use_weight until next reload. */
1087 } else if (!strcasecmp(param, "timeoutrestart")) {
1088 q->timeoutrestart = ast_true(val);
1089 } else if (failunknown) {
1090 if (linenum >= 0) {
1091 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
1092 q->name, param, linenum);
1093 } else {
1094 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
1099 static void rt_handle_member_record(struct call_queue *q, char *interface, const char *membername, const char *penalty_str, const char *paused_str)
1101 struct member *m, tmpmem;
1102 int penalty = 0;
1103 int paused = 0;
1105 if (penalty_str) {
1106 penalty = atoi(penalty_str);
1107 if (penalty < 0)
1108 penalty = 0;
1111 if (paused_str) {
1112 paused = atoi(paused_str);
1113 if (paused < 0)
1114 paused = 0;
1117 /* Find the member, or the place to put a new one. */
1118 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
1119 m = ao2_find(q->members, &tmpmem, OBJ_POINTER);
1121 /* Create a new one if not found, else update penalty */
1122 if (!m) {
1123 if ((m = create_queue_member(interface, membername, penalty, paused))) {
1124 m->dead = 0;
1125 m->realtime = 1;
1126 add_to_interfaces(interface);
1127 ao2_link(q->members, m);
1128 ao2_ref(m, -1);
1129 m = NULL;
1130 q->membercount++;
1132 } else {
1133 m->dead = 0; /* Do not delete this one. */
1134 if (paused_str)
1135 m->paused = paused;
1136 m->penalty = penalty;
1137 ao2_ref(m, -1);
1141 static void free_members(struct call_queue *q, int all)
1143 /* Free non-dynamic members */
1144 struct member *cur;
1145 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
1147 while ((cur = ao2_iterator_next(&mem_iter))) {
1148 if (all || !cur->dynamic) {
1149 ao2_unlink(q->members, cur);
1150 remove_from_interfaces(cur->interface);
1151 q->membercount--;
1153 ao2_ref(cur, -1);
1157 static void destroy_queue(struct call_queue *q)
1159 free_members(q, 1);
1160 ast_mutex_destroy(&q->lock);
1161 ao2_ref(q->members, -1);
1162 free(q);
1165 /*!\brief Reload a single queue via realtime.
1166 \return Return the queue, or NULL if it doesn't exist.
1167 \note Should be called with the global qlock locked. */
1168 static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
1170 struct ast_variable *v;
1171 struct call_queue *q;
1172 struct member *m;
1173 struct ao2_iterator mem_iter;
1174 char *interface = NULL;
1175 char *tmp, *tmp_name;
1176 char tmpbuf[64]; /* Must be longer than the longest queue param name. */
1178 /* Find the queue in the in-core list (we will create a new one if not found). */
1179 AST_LIST_TRAVERSE(&queues, q, list) {
1180 if (!strcasecmp(q->name, queuename))
1181 break;
1184 /* Static queues override realtime. */
1185 if (q) {
1186 ast_mutex_lock(&q->lock);
1187 if (!q->realtime) {
1188 if (q->dead) {
1189 ast_mutex_unlock(&q->lock);
1190 return NULL;
1191 } else {
1192 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
1193 ast_mutex_unlock(&q->lock);
1194 return q;
1197 } else if (!member_config)
1198 /* Not found in the list, and it's not realtime ... */
1199 return NULL;
1201 /* Check if queue is defined in realtime. */
1202 if (!queue_vars) {
1203 /* Delete queue from in-core list if it has been deleted in realtime. */
1204 if (q) {
1205 /*! \note Hmm, can't seem to distinguish a DB failure from a not
1206 found condition... So we might delete an in-core queue
1207 in case of DB failure. */
1208 ast_log(LOG_DEBUG, "Queue %s not found in realtime.\n", queuename);
1210 q->dead = 1;
1211 /* Delete if unused (else will be deleted when last caller leaves). */
1212 if (!q->count) {
1213 /* Delete. */
1214 AST_LIST_REMOVE(&queues, q, list);
1215 ast_mutex_unlock(&q->lock);
1216 destroy_queue(q);
1217 } else
1218 ast_mutex_unlock(&q->lock);
1220 return NULL;
1223 /* Create a new queue if an in-core entry does not exist yet. */
1224 if (!q) {
1225 if (!(q = alloc_queue(queuename)))
1226 return NULL;
1227 ast_mutex_lock(&q->lock);
1228 clear_queue(q);
1229 q->realtime = 1;
1230 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
1231 AST_LIST_INSERT_HEAD(&queues, q, list);
1234 memset(tmpbuf, 0, sizeof(tmpbuf));
1235 for (v = queue_vars; v; v = v->next) {
1236 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
1237 if ((tmp = strchr(v->name, '_'))) {
1238 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
1239 tmp_name = tmpbuf;
1240 tmp = tmp_name;
1241 while ((tmp = strchr(tmp, '_')))
1242 *tmp++ = '-';
1243 } else
1244 tmp_name = v->name;
1246 if (!ast_strlen_zero(v->value)) {
1247 /* Don't want to try to set the option if the value is empty */
1248 queue_set_param(q, tmp_name, v->value, -1, 0);
1252 if (q->strategy == QUEUE_STRATEGY_ROUNDROBIN)
1253 rr_dep_warning();
1255 /* Temporarily set realtime members dead so we can detect deleted ones.
1256 * Also set the membercount correctly for realtime*/
1257 mem_iter = ao2_iterator_init(q->members, 0);
1258 while ((m = ao2_iterator_next(&mem_iter))) {
1259 q->membercount++;
1260 if (m->realtime)
1261 m->dead = 1;
1262 ao2_ref(m, -1);
1265 while ((interface = ast_category_browse(member_config, interface))) {
1266 rt_handle_member_record(q, interface,
1267 ast_variable_retrieve(member_config, interface, "membername"),
1268 ast_variable_retrieve(member_config, interface, "penalty"),
1269 ast_variable_retrieve(member_config, interface, "paused"));
1272 /* Delete all realtime members that have been deleted in DB. */
1273 mem_iter = ao2_iterator_init(q->members, 0);
1274 while ((m = ao2_iterator_next(&mem_iter))) {
1275 if (m->dead) {
1276 ao2_unlink(q->members, m);
1277 ast_mutex_unlock(&q->lock);
1278 remove_from_interfaces(m->interface);
1279 ast_mutex_lock(&q->lock);
1280 q->membercount--;
1282 ao2_ref(m, -1);
1285 ast_mutex_unlock(&q->lock);
1287 return q;
1290 static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
1292 struct ast_variable *var;
1293 int ret = -1;
1295 if (!(var = ast_load_realtime("queue_members", "interface", mem->interface, "queue_name", queue_name, NULL)))
1296 return ret;
1297 while (var) {
1298 if (!strcmp(var->name, "uniqueid"))
1299 break;
1300 var = var->next;
1302 if (var && !ast_strlen_zero(var->value)) {
1303 if ((ast_update_realtime("queue_members", "uniqueid", var->value, field, value, NULL)) > -1)
1304 ret = 0;
1306 return ret;
1309 static void update_realtime_members(struct call_queue *q)
1311 struct ast_config *member_config = NULL;
1312 struct member *m;
1313 char *interface = NULL;
1314 struct ao2_iterator mem_iter;
1316 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , NULL))) {
1317 /*This queue doesn't have realtime members*/
1318 if (option_debug > 2)
1319 ast_log(LOG_DEBUG, "Queue %s has no realtime members defined. No need for update\n", q->name);
1320 return;
1323 ast_mutex_lock(&q->lock);
1325 /* Temporarily set realtime members dead so we can detect deleted ones.*/
1326 mem_iter = ao2_iterator_init(q->members, 0);
1327 while ((m = ao2_iterator_next(&mem_iter))) {
1328 if (m->realtime)
1329 m->dead = 1;
1330 ao2_ref(m, -1);
1333 while ((interface = ast_category_browse(member_config, interface))) {
1334 rt_handle_member_record(q, interface,
1335 S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
1336 ast_variable_retrieve(member_config, interface, "penalty"),
1337 ast_variable_retrieve(member_config, interface, "paused"));
1340 /* Delete all realtime members that have been deleted in DB. */
1341 mem_iter = ao2_iterator_init(q->members, 0);
1342 while ((m = ao2_iterator_next(&mem_iter))) {
1343 if (m->dead) {
1344 ao2_unlink(q->members, m);
1345 ast_mutex_unlock(&q->lock);
1346 remove_from_interfaces(m->interface);
1347 ast_mutex_lock(&q->lock);
1348 q->membercount--;
1350 ao2_ref(m, -1);
1352 ast_mutex_unlock(&q->lock);
1353 ast_config_destroy(member_config);
1356 static struct call_queue *load_realtime_queue(const char *queuename)
1358 struct ast_variable *queue_vars;
1359 struct ast_config *member_config = NULL;
1360 struct call_queue *q;
1362 /* Find the queue in the in-core list first. */
1363 AST_LIST_LOCK(&queues);
1364 AST_LIST_TRAVERSE(&queues, q, list) {
1365 if (!strcasecmp(q->name, queuename)) {
1366 break;
1369 AST_LIST_UNLOCK(&queues);
1371 if (!q || q->realtime) {
1372 /*! \note Load from realtime before taking the global qlock, to avoid blocking all
1373 queue operations while waiting for the DB.
1375 This will be two separate database transactions, so we might
1376 see queue parameters as they were before another process
1377 changed the queue and member list as it was after the change.
1378 Thus we might see an empty member list when a queue is
1379 deleted. In practise, this is unlikely to cause a problem. */
1381 queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
1382 if (queue_vars) {
1383 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
1384 if (!member_config) {
1385 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
1386 ast_variables_destroy(queue_vars);
1387 return NULL;
1391 AST_LIST_LOCK(&queues);
1393 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
1394 if (member_config)
1395 ast_config_destroy(member_config);
1396 if (queue_vars)
1397 ast_variables_destroy(queue_vars);
1399 AST_LIST_UNLOCK(&queues);
1400 } else {
1401 update_realtime_members(q);
1403 return q;
1406 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
1408 struct call_queue *q;
1409 struct queue_ent *cur, *prev = NULL;
1410 int res = -1;
1411 int pos = 0;
1412 int inserted = 0;
1413 enum queue_member_status stat;
1415 if (!(q = load_realtime_queue(queuename)))
1416 return res;
1418 AST_LIST_LOCK(&queues);
1419 ast_mutex_lock(&q->lock);
1421 /* This is our one */
1422 stat = get_member_status(q, qe->max_penalty);
1423 if (!q->joinempty && (stat == QUEUE_NO_MEMBERS))
1424 *reason = QUEUE_JOINEMPTY;
1425 else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS))
1426 *reason = QUEUE_JOINUNAVAIL;
1427 else if (q->maxlen && (q->count >= q->maxlen))
1428 *reason = QUEUE_FULL;
1429 else {
1430 /* There's space for us, put us at the right position inside
1431 * the queue.
1432 * Take into account the priority of the calling user */
1433 inserted = 0;
1434 prev = NULL;
1435 cur = q->head;
1436 while (cur) {
1437 /* We have higher priority than the current user, enter
1438 * before him, after all the other users with priority
1439 * higher or equal to our priority. */
1440 if ((!inserted) && (qe->prio > cur->prio)) {
1441 insert_entry(q, prev, qe, &pos);
1442 inserted = 1;
1444 cur->pos = ++pos;
1445 prev = cur;
1446 cur = cur->next;
1448 /* No luck, join at the end of the queue */
1449 if (!inserted)
1450 insert_entry(q, prev, qe, &pos);
1451 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
1452 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
1453 ast_copy_string(qe->context, q->context, sizeof(qe->context));
1454 q->count++;
1455 res = 0;
1456 manager_event(EVENT_FLAG_CALL, "Join",
1457 "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
1458 qe->chan->name,
1459 S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */
1460 S_OR(qe->chan->cid.cid_name, "unknown"),
1461 q->name, qe->pos, q->count, qe->chan->uniqueid );
1462 if (option_debug)
1463 ast_log(LOG_DEBUG, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
1465 ast_mutex_unlock(&q->lock);
1466 AST_LIST_UNLOCK(&queues);
1468 return res;
1471 static int play_file(struct ast_channel *chan, char *filename)
1473 int res;
1475 ast_stopstream(chan);
1477 res = ast_streamfile(chan, filename, chan->language);
1478 if (!res)
1479 res = ast_waitstream(chan, AST_DIGIT_ANY);
1481 ast_stopstream(chan);
1483 return res;
1486 static int valid_exit(struct queue_ent *qe, char digit)
1488 int digitlen = strlen(qe->digits);
1490 /* Prevent possible buffer overflow */
1491 if (digitlen < sizeof(qe->digits) - 2) {
1492 qe->digits[digitlen] = digit;
1493 qe->digits[digitlen + 1] = '\0';
1494 } else {
1495 qe->digits[0] = '\0';
1496 return 0;
1499 /* If there's no context to goto, short-circuit */
1500 if (ast_strlen_zero(qe->context))
1501 return 0;
1503 /* If the extension is bad, then reset the digits to blank */
1504 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) {
1505 qe->digits[0] = '\0';
1506 return 0;
1509 /* We have an exact match */
1510 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
1511 qe->valid_digits = 1;
1512 /* Return 1 on a successful goto */
1513 return 1;
1516 return 0;
1519 static int say_position(struct queue_ent *qe)
1521 int res = 0, avgholdmins, avgholdsecs;
1522 time_t now;
1524 /* Check to see if this is ludicrous -- if we just announced position, don't do it again*/
1525 time(&now);
1526 if ((now - qe->last_pos) < 15)
1527 return 0;
1529 /* If either our position has changed, or we are over the freq timer, say position */
1530 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency))
1531 return 0;
1533 ast_moh_stop(qe->chan);
1534 /* Say we're next, if we are */
1535 if (qe->pos == 1) {
1536 res = play_file(qe->chan, qe->parent->sound_next);
1537 if (res)
1538 goto playout;
1539 else
1540 goto posout;
1541 } else {
1542 res = play_file(qe->chan, qe->parent->sound_thereare);
1543 if (res)
1544 goto playout;
1545 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */
1546 if (res)
1547 goto playout;
1548 res = play_file(qe->chan, qe->parent->sound_calls);
1549 if (res)
1550 goto playout;
1552 /* Round hold time to nearest minute */
1553 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
1555 /* If they have specified a rounding then round the seconds as well */
1556 if (qe->parent->roundingseconds) {
1557 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
1558 avgholdsecs *= qe->parent->roundingseconds;
1559 } else {
1560 avgholdsecs = 0;
1563 if (option_verbose > 2)
1564 ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
1566 /* If the hold time is >1 min, if it's enabled, and if it's not
1567 supposed to be only once and we have already said it, say it */
1568 if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) &&
1569 (!(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE) && qe->last_pos)) {
1570 res = play_file(qe->chan, qe->parent->sound_holdtime);
1571 if (res)
1572 goto playout;
1574 if (avgholdmins > 0) {
1575 if (avgholdmins < 2) {
1576 res = play_file(qe->chan, qe->parent->sound_lessthan);
1577 if (res)
1578 goto playout;
1580 res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, NULL);
1581 if (res)
1582 goto playout;
1583 } else {
1584 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL);
1585 if (res)
1586 goto playout;
1589 res = play_file(qe->chan, qe->parent->sound_minutes);
1590 if (res)
1591 goto playout;
1593 if (avgholdsecs>0) {
1594 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL);
1595 if (res)
1596 goto playout;
1598 res = play_file(qe->chan, qe->parent->sound_seconds);
1599 if (res)
1600 goto playout;
1605 posout:
1606 if (option_verbose > 2)
1607 ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n",
1608 qe->chan->name, qe->parent->name, qe->pos);
1609 res = play_file(qe->chan, qe->parent->sound_thanks);
1611 playout:
1612 if ((res > 0 && !valid_exit(qe, res)) || res < 0)
1613 res = 0;
1615 /* Set our last_pos indicators */
1616 qe->last_pos = now;
1617 qe->last_pos_said = qe->pos;
1619 /* Don't restart music on hold if we're about to exit the caller from the queue */
1620 if (!res)
1621 ast_moh_start(qe->chan, qe->moh, NULL);
1623 return res;
1626 static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
1628 int oldvalue;
1630 /* Calculate holdtime using a recursive boxcar filter */
1631 /* Thanks to SRT for this contribution */
1632 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
1634 ast_mutex_lock(&qe->parent->lock);
1635 oldvalue = qe->parent->holdtime;
1636 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
1637 ast_mutex_unlock(&qe->parent->lock);
1641 static void leave_queue(struct queue_ent *qe)
1643 struct call_queue *q;
1644 struct queue_ent *cur, *prev = NULL;
1645 int pos = 0;
1647 if (!(q = qe->parent))
1648 return;
1649 ast_mutex_lock(&q->lock);
1651 prev = NULL;
1652 for (cur = q->head; cur; cur = cur->next) {
1653 if (cur == qe) {
1654 q->count--;
1656 /* Take us out of the queue */
1657 manager_event(EVENT_FLAG_CALL, "Leave",
1658 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nUniqueid: %s\r\n",
1659 qe->chan->name, q->name, q->count, qe->chan->uniqueid);
1660 if (option_debug)
1661 ast_log(LOG_DEBUG, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
1662 /* Take us out of the queue */
1663 if (prev)
1664 prev->next = cur->next;
1665 else
1666 q->head = cur->next;
1667 } else {
1668 /* Renumber the people after us in the queue based on a new count */
1669 cur->pos = ++pos;
1670 prev = cur;
1673 ast_mutex_unlock(&q->lock);
1675 if (q->dead && !q->count) {
1676 /* It's dead and nobody is in it, so kill it */
1677 AST_LIST_LOCK(&queues);
1678 AST_LIST_REMOVE(&queues, q, list);
1679 AST_LIST_UNLOCK(&queues);
1680 destroy_queue(q);
1684 /* Hang up a list of outgoing calls */
1685 static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception)
1687 struct callattempt *oo;
1689 while (outgoing) {
1690 /* Hangup any existing lines we have open */
1691 if (outgoing->chan && (outgoing->chan != exception))
1692 ast_hangup(outgoing->chan);
1693 oo = outgoing;
1694 outgoing = outgoing->q_next;
1695 if (oo->member)
1696 ao2_ref(oo->member, -1);
1697 free(oo);
1702 /* traverse all defined queues which have calls waiting and contain this member
1703 return 0 if no other queue has precedence (higher weight) or 1 if found */
1704 static int compare_weight(struct call_queue *rq, struct member *member)
1706 struct call_queue *q;
1707 struct member *mem;
1708 int found = 0;
1710 /* &qlock and &rq->lock already set by try_calling()
1711 * to solve deadlock */
1712 AST_LIST_TRAVERSE(&queues, q, list) {
1713 if (q == rq) /* don't check myself, could deadlock */
1714 continue;
1715 ast_mutex_lock(&q->lock);
1716 if (q->count && q->members) {
1717 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
1718 ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
1719 if (q->weight > rq->weight) {
1720 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);
1721 found = 1;
1723 ao2_ref(mem, -1);
1726 ast_mutex_unlock(&q->lock);
1727 if (found)
1728 break;
1730 return found;
1733 /*! \brief common hangup actions */
1734 static void do_hang(struct callattempt *o)
1736 o->stillgoing = 0;
1737 ast_hangup(o->chan);
1738 o->chan = NULL;
1741 static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
1743 char *tmp = alloca(len);
1745 if (pbx_builtin_serialize_variables(chan, tmp, len)) {
1746 int i, j;
1748 /* convert "\n" to "\nVariable: " */
1749 strcpy(vars, "Variable: ");
1751 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) {
1752 vars[j] = tmp[i];
1754 if (tmp[i + 1] == '\0')
1755 break;
1756 if (tmp[i] == '\n') {
1757 vars[j++] = '\r';
1758 vars[j++] = '\n';
1760 ast_copy_string(&(vars[j]), "Variable: ", len - j);
1761 j += 9;
1764 if (j > len - 1)
1765 j = len - 1;
1766 vars[j - 2] = '\r';
1767 vars[j - 1] = '\n';
1768 vars[j] = '\0';
1769 } else {
1770 /* there are no channel variables; leave it blank */
1771 *vars = '\0';
1773 return vars;
1776 /*! \brief Part 2 of ring_one
1778 * Does error checking before attempting to request a channel and call a member. This
1779 * function is only called from ring_one
1781 static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
1783 int res;
1784 int status;
1785 char tech[256];
1786 char *location;
1788 /* on entry here, we know that tmp->chan == NULL */
1789 if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
1790 if (option_debug)
1791 ast_log(LOG_DEBUG, "Wrapuptime not yet expired for %s\n", tmp->interface);
1792 if (qe->chan->cdr)
1793 ast_cdr_busy(qe->chan->cdr);
1794 tmp->stillgoing = 0;
1795 (*busies)++;
1796 return 0;
1799 if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
1800 if (option_debug)
1801 ast_log(LOG_DEBUG, "%s in use, can't receive call\n", tmp->interface);
1802 if (qe->chan->cdr)
1803 ast_cdr_busy(qe->chan->cdr);
1804 tmp->stillgoing = 0;
1805 return 0;
1808 if (tmp->member->paused) {
1809 if (option_debug)
1810 ast_log(LOG_DEBUG, "%s paused, can't receive call\n", tmp->interface);
1811 if (qe->chan->cdr)
1812 ast_cdr_busy(qe->chan->cdr);
1813 tmp->stillgoing = 0;
1814 return 0;
1816 if (use_weight && compare_weight(qe->parent,tmp->member)) {
1817 ast_log(LOG_DEBUG, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
1818 if (qe->chan->cdr)
1819 ast_cdr_busy(qe->chan->cdr);
1820 tmp->stillgoing = 0;
1821 (*busies)++;
1822 return 0;
1825 ast_copy_string(tech, tmp->interface, sizeof(tech));
1826 if ((location = strchr(tech, '/')))
1827 *location++ = '\0';
1828 else
1829 location = "";
1831 /* Request the peer */
1832 tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
1833 if (!tmp->chan) { /* If we can't, just go on to the next call */
1834 if (qe->chan->cdr)
1835 ast_cdr_busy(qe->chan->cdr);
1836 tmp->stillgoing = 0;
1838 update_status(tmp->member->interface, ast_device_state(tmp->member->interface));
1840 ast_mutex_lock(&qe->parent->lock);
1841 qe->parent->rrpos++;
1842 ast_mutex_unlock(&qe->parent->lock);
1844 (*busies)++;
1845 return 0;
1848 tmp->chan->appl = "AppQueue";
1849 tmp->chan->data = "(Outgoing Line)";
1850 tmp->chan->whentohangup = 0;
1851 if (tmp->chan->cid.cid_num)
1852 free(tmp->chan->cid.cid_num);
1853 tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num);
1854 if (tmp->chan->cid.cid_name)
1855 free(tmp->chan->cid.cid_name);
1856 tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name);
1857 if (tmp->chan->cid.cid_ani)
1858 free(tmp->chan->cid.cid_ani);
1859 tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani);
1861 /* Inherit specially named variables from parent channel */
1862 ast_channel_inherit_variables(qe->chan, tmp->chan);
1864 /* Presense of ADSI CPE on outgoing channel follows ours */
1865 tmp->chan->adsicpe = qe->chan->adsicpe;
1867 /* Inherit context and extension */
1868 if (!ast_strlen_zero(qe->chan->macrocontext))
1869 ast_copy_string(tmp->chan->dialcontext, qe->chan->macrocontext, sizeof(tmp->chan->dialcontext));
1870 else
1871 ast_copy_string(tmp->chan->dialcontext, qe->chan->context, sizeof(tmp->chan->dialcontext));
1872 if (!ast_strlen_zero(qe->chan->macroexten))
1873 ast_copy_string(tmp->chan->exten, qe->chan->macroexten, sizeof(tmp->chan->exten));
1874 else
1875 ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten));
1877 /* Place the call, but don't wait on the answer */
1878 if ((res = ast_call(tmp->chan, location, 0))) {
1879 /* Again, keep going even if there's an error */
1880 if (option_debug)
1881 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
1882 if (option_verbose > 2)
1883 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface);
1884 do_hang(tmp);
1885 (*busies)++;
1886 return 0;
1887 } else if (qe->parent->eventwhencalled) {
1888 char vars[2048];
1890 manager_event(EVENT_FLAG_AGENT, "AgentCalled",
1891 "AgentCalled: %s\r\n"
1892 "AgentName: %s\r\n"
1893 "ChannelCalling: %s\r\n"
1894 "CallerID: %s\r\n"
1895 "CallerIDName: %s\r\n"
1896 "Context: %s\r\n"
1897 "Extension: %s\r\n"
1898 "Priority: %d\r\n"
1899 "%s",
1900 tmp->interface, tmp->member->membername, qe->chan->name,
1901 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
1902 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
1903 qe->chan->context, qe->chan->exten, qe->chan->priority,
1904 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
1905 if (option_verbose > 2)
1906 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface);
1909 return 1;
1912 /*! \brief find the entry with the best metric, or NULL */
1913 static struct callattempt *find_best(struct callattempt *outgoing)
1915 struct callattempt *best = NULL, *cur;
1917 for (cur = outgoing; cur; cur = cur->q_next) {
1918 if (cur->stillgoing && /* Not already done */
1919 !cur->chan && /* Isn't already going */
1920 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */
1921 best = cur;
1925 return best;
1928 /*! \brief Place a call to a queue member
1930 * Once metrics have been calculated for each member, this function is used
1931 * to place a call to the appropriate member (or members). The low-level
1932 * channel-handling and error detection is handled in ring_entry
1934 * Returns 1 if a member was called successfully, 0 otherwise
1936 static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
1938 int ret = 0;
1940 while (ret == 0) {
1941 struct callattempt *best = find_best(outgoing);
1942 if (!best) {
1943 if (option_debug)
1944 ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n");
1945 break;
1947 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
1948 struct callattempt *cur;
1949 /* Ring everyone who shares this best metric (for ringall) */
1950 for (cur = outgoing; cur; cur = cur->q_next) {
1951 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
1952 if (option_debug)
1953 ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
1954 ret |= ring_entry(qe, cur, busies);
1957 } else {
1958 /* Ring just the best channel */
1959 if (option_debug)
1960 ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric);
1961 ret = ring_entry(qe, best, busies);
1965 return ret;
1968 static int store_next(struct queue_ent *qe, struct callattempt *outgoing)
1970 struct callattempt *best = find_best(outgoing);
1972 if (best) {
1973 /* Ring just the best channel */
1974 if (option_debug)
1975 ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric);
1976 qe->parent->rrpos = best->metric % 1000;
1977 } else {
1978 /* Just increment rrpos */
1979 if (qe->parent->wrapped) {
1980 /* No more channels, start over */
1981 qe->parent->rrpos = 0;
1982 } else {
1983 /* Prioritize next entry */
1984 qe->parent->rrpos++;
1987 qe->parent->wrapped = 0;
1989 return 0;
1992 static int say_periodic_announcement(struct queue_ent *qe)
1994 int res = 0;
1995 time_t now;
1997 /* Get the current time */
1998 time(&now);
2000 /* Check to see if it is time to announce */
2001 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
2002 return 0;
2004 /* Stop the music on hold so we can play our own file */
2005 ast_moh_stop(qe->chan);
2007 if (option_verbose > 2)
2008 ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n");
2010 /* Check to make sure we have a sound file. If not, reset to the first sound file */
2011 if (qe->last_periodic_announce_sound >= MAX_PERIODIC_ANNOUNCEMENTS || !strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound])) {
2012 qe->last_periodic_announce_sound = 0;
2015 /* play the announcement */
2016 res = play_file(qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]);
2018 if ((res > 0 && !valid_exit(qe, res)) || res < 0)
2019 res = 0;
2021 /* Resume Music on Hold if the caller is going to stay in the queue */
2022 if (!res)
2023 ast_moh_start(qe->chan, qe->moh, NULL);
2025 /* update last_periodic_announce_time */
2026 qe->last_periodic_announce_time = now;
2028 /* Update the current periodic announcement to the next announcement */
2029 qe->last_periodic_announce_sound++;
2031 return res;
2034 static void record_abandoned(struct queue_ent *qe)
2036 ast_mutex_lock(&qe->parent->lock);
2037 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
2038 "Queue: %s\r\n"
2039 "Uniqueid: %s\r\n"
2040 "Position: %d\r\n"
2041 "OriginalPosition: %d\r\n"
2042 "HoldTime: %d\r\n",
2043 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start));
2045 qe->parent->callsabandoned++;
2046 ast_mutex_unlock(&qe->parent->lock);
2049 /*! \brief RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. */
2050 static void rna(int rnatime, struct queue_ent *qe, char *interface, char *membername)
2052 if (option_verbose > 2)
2053 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", rnatime);
2054 ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
2055 if (qe->parent->autopause) {
2056 if (!set_member_paused(qe->parent->name, interface, 1)) {
2057 if (option_verbose > 2)
2058 ast_verbose( VERBOSE_PREFIX_3 "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name);
2059 } else {
2060 if (option_verbose > 2)
2061 ast_verbose( VERBOSE_PREFIX_3 "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
2064 return;
2067 #define AST_MAX_WATCHERS 256
2068 /*! \brief Wait for a member to answer the call
2070 * \param[in] qe the queue_ent corresponding to the caller in the queue
2071 * \param[in] outgoing the list of callattempts. Relevant ones will have their chan and stillgoing parameters non-zero
2072 * \param[in] to the amount of time (in milliseconds) to wait for a response
2073 * \param[out] digit if a user presses a digit to exit the queue, this is the digit the caller pressed
2074 * \param[in] prebusies number of busy members calculated prior to calling wait_for_answer
2075 * \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
2076 * \param[in] forwardsallowed used to detect if we should allow call forwarding, based on the 'i' option to Queue()
2078 static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
2080 char *queue = qe->parent->name;
2081 struct callattempt *o, *start = NULL, *prev = NULL;
2082 int status;
2083 int numbusies = prebusies;
2084 int numnochan = 0;
2085 int stillgoing = 0;
2086 int orig = *to;
2087 struct ast_frame *f;
2088 struct callattempt *peer = NULL;
2089 struct ast_channel *winner;
2090 struct ast_channel *in = qe->chan;
2091 char on[80] = "";
2092 char membername[80] = "";
2093 long starttime = 0;
2094 long endtime = 0;
2096 starttime = (long) time(NULL);
2098 while (*to && !peer) {
2099 int numlines, retry, pos = 1;
2100 struct ast_channel *watchers[AST_MAX_WATCHERS];
2101 watchers[0] = in;
2102 start = NULL;
2104 for (retry = 0; retry < 2; retry++) {
2105 numlines = 0;
2106 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
2107 if (o->stillgoing) { /* Keep track of important channels */
2108 stillgoing = 1;
2109 if (o->chan) {
2110 watchers[pos++] = o->chan;
2111 if (!start)
2112 start = o;
2113 else
2114 prev->call_next = o;
2115 prev = o;
2118 numlines++;
2120 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
2121 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */)
2122 break;
2123 /* On "ringall" strategy we only move to the next penalty level
2124 when *all* ringing phones are done in the current penalty level */
2125 ring_one(qe, outgoing, &numbusies);
2126 /* and retry... */
2128 if (pos == 1 /* not found */) {
2129 if (numlines == (numbusies + numnochan)) {
2130 ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
2131 } else {
2132 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan);
2134 *to = 0;
2135 return NULL;
2137 winner = ast_waitfor_n(watchers, pos, to);
2138 for (o = start; o; o = o->call_next) {
2139 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
2140 if (!peer) {
2141 if (option_verbose > 2)
2142 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
2143 peer = o;
2145 } else if (o->chan && (o->chan == winner)) {
2147 ast_copy_string(on, o->member->interface, sizeof(on));
2148 ast_copy_string(membername, o->member->membername, sizeof(membername));
2150 if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) {
2151 if (option_verbose > 2)
2152 ast_verbose(VERBOSE_PREFIX_3 "Forwarding %s to '%s' prevented.\n", in->name, o->chan->call_forward);
2153 numnochan++;
2154 do_hang(o);
2155 winner = NULL;
2156 continue;
2157 } else if (!ast_strlen_zero(o->chan->call_forward)) {
2158 char tmpchan[256];
2159 char *stuff;
2160 char *tech;
2162 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
2163 if ((stuff = strchr(tmpchan, '/'))) {
2164 *stuff++ = '\0';
2165 tech = tmpchan;
2166 } else {
2167 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
2168 stuff = tmpchan;
2169 tech = "Local";
2171 /* Before processing channel, go ahead and check for forwarding */
2172 if (option_verbose > 2)
2173 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
2174 /* Setup parameters */
2175 o->chan = ast_request(tech, in->nativeformats, stuff, &status);
2176 if (!o->chan) {
2177 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
2178 o->stillgoing = 0;
2179 numnochan++;
2180 } else {
2181 ast_channel_inherit_variables(in, o->chan);
2182 ast_channel_datastore_inherit(in, o->chan);
2183 if (o->chan->cid.cid_num)
2184 free(o->chan->cid.cid_num);
2185 o->chan->cid.cid_num = ast_strdup(in->cid.cid_num);
2187 if (o->chan->cid.cid_name)
2188 free(o->chan->cid.cid_name);
2189 o->chan->cid.cid_name = ast_strdup(in->cid.cid_name);
2191 ast_string_field_set(o->chan, accountcode, in->accountcode);
2192 o->chan->cdrflags = in->cdrflags;
2194 if (in->cid.cid_ani) {
2195 if (o->chan->cid.cid_ani)
2196 free(o->chan->cid.cid_ani);
2197 o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani);
2199 if (o->chan->cid.cid_rdnis)
2200 free(o->chan->cid.cid_rdnis);
2201 o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten));
2202 if (ast_call(o->chan, tmpchan, 0)) {
2203 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
2204 do_hang(o);
2205 numnochan++;
2208 /* Hangup the original channel now, in case we needed it */
2209 ast_hangup(winner);
2210 continue;
2212 f = ast_read(winner);
2213 if (f) {
2214 if (f->frametype == AST_FRAME_CONTROL) {
2215 switch (f->subclass) {
2216 case AST_CONTROL_ANSWER:
2217 /* This is our guy if someone answered. */
2218 if (!peer) {
2219 if (option_verbose > 2)
2220 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
2221 peer = o;
2223 break;
2224 case AST_CONTROL_BUSY:
2225 if (option_verbose > 2)
2226 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
2227 if (in->cdr)
2228 ast_cdr_busy(in->cdr);
2229 do_hang(o);
2230 endtime = (long)time(NULL);
2231 endtime -= starttime;
2232 rna(endtime*1000, qe, on, membername);
2233 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2234 if (qe->parent->timeoutrestart)
2235 *to = orig;
2236 ring_one(qe, outgoing, &numbusies);
2238 numbusies++;
2239 break;
2240 case AST_CONTROL_CONGESTION:
2241 if (option_verbose > 2)
2242 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
2243 if (in->cdr)
2244 ast_cdr_busy(in->cdr);
2245 endtime = (long)time(NULL);
2246 endtime -= starttime;
2247 rna(endtime*1000, qe, on, membername);
2248 do_hang(o);
2249 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2250 if (qe->parent->timeoutrestart)
2251 *to = orig;
2252 ring_one(qe, outgoing, &numbusies);
2254 numbusies++;
2255 break;
2256 case AST_CONTROL_RINGING:
2257 if (option_verbose > 2)
2258 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
2259 break;
2260 case AST_CONTROL_OFFHOOK:
2261 /* Ignore going off hook */
2262 break;
2263 default:
2264 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
2267 ast_frfree(f);
2268 } else {
2269 endtime = (long) time(NULL) - starttime;
2270 rna(endtime * 1000, qe, on, membername);
2271 do_hang(o);
2272 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2273 if (qe->parent->timeoutrestart)
2274 *to = orig;
2275 ring_one(qe, outgoing, &numbusies);
2280 if (winner == in) {
2281 f = ast_read(in);
2282 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
2283 /* Got hung up */
2284 *to = -1;
2285 if (f)
2286 ast_frfree(f);
2287 return NULL;
2289 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) {
2290 if (option_verbose > 3)
2291 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
2292 *to = 0;
2293 ast_frfree(f);
2294 return NULL;
2296 if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass)) {
2297 if (option_verbose > 3)
2298 ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass);
2299 *to = 0;
2300 *digit = f->subclass;
2301 ast_frfree(f);
2302 return NULL;
2304 ast_frfree(f);
2306 if (!*to) {
2307 for (o = start; o; o = o->call_next)
2308 rna(orig, qe, o->interface, o->member->membername);
2312 return peer;
2314 /*! \brief Check if we should start attempting to call queue members
2316 * The behavior of this function is dependent first on whether autofill is enabled
2317 * and second on whether the ring strategy is ringall. If autofill is not enabled,
2318 * then return true if we're the head of the queue. If autofill is enabled, then
2319 * we count the available members and see if the number of available members is enough
2320 * that given our position in the queue, we would theoretically be able to connect to
2321 * one of those available members
2323 static int is_our_turn(struct queue_ent *qe)
2325 struct queue_ent *ch;
2326 struct member *cur;
2327 int avl = 0;
2328 int idx = 0;
2329 int res;
2331 if (!qe->parent->autofill) {
2332 /* Atomically read the parent head -- does not need a lock */
2333 ch = qe->parent->head;
2334 /* If we are now at the top of the head, break out */
2335 if (ch == qe) {
2336 if (option_debug)
2337 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
2338 res = 1;
2339 } else {
2340 if (option_debug)
2341 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
2342 res = 0;
2345 } else {
2346 /* This needs a lock. How many members are available to be served? */
2347 ast_mutex_lock(&qe->parent->lock);
2349 ch = qe->parent->head;
2351 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
2352 if (option_debug)
2353 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");
2354 avl = 1;
2355 } else {
2356 struct ao2_iterator mem_iter = ao2_iterator_init(qe->parent->members, 0);
2357 while ((cur = ao2_iterator_next(&mem_iter))) {
2358 switch (cur->status) {
2359 case AST_DEVICE_INUSE:
2360 if (!qe->parent->ringinuse)
2361 break;
2362 /* else fall through */
2363 case AST_DEVICE_NOT_INUSE:
2364 case AST_DEVICE_UNKNOWN:
2365 if (!cur->paused)
2366 avl++;
2367 break;
2369 ao2_ref(cur, -1);
2373 if (option_debug)
2374 ast_log(LOG_DEBUG, "There are %d available members.\n", avl);
2376 while ((idx < avl) && (ch) && (ch != qe)) {
2377 if (!ch->pending)
2378 idx++;
2379 ch = ch->next;
2382 /* If the queue entry is within avl [the number of available members] calls from the top ... */
2383 if (ch && idx < avl) {
2384 if (option_debug)
2385 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
2386 res = 1;
2387 } else {
2388 if (option_debug)
2389 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
2390 res = 0;
2393 ast_mutex_unlock(&qe->parent->lock);
2396 return res;
2398 /*! \brief The waiting areas for callers who are not actively calling members
2400 * This function is one large loop. This function will return if a caller
2401 * either exits the queue or it becomes that caller's turn to attempt calling
2402 * queue members. Inside the loop, we service the caller with periodic announcements,
2403 * holdtime announcements, etc. as configured in queues.conf
2405 * \retval 0 if the caller's turn has arrived
2406 * \retval -1 if the caller should exit the queue.
2408 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
2410 int res = 0;
2412 /* This is the holding pen for callers 2 through maxlen */
2413 for (;;) {
2414 enum queue_member_status stat;
2416 if (is_our_turn(qe))
2417 break;
2419 /* If we have timed out, break out */
2420 if (qe->expire && (time(NULL) > qe->expire)) {
2421 *reason = QUEUE_TIMEOUT;
2422 break;
2425 stat = get_member_status(qe->parent, qe->max_penalty);
2427 /* leave the queue if no agents, if enabled */
2428 if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
2429 *reason = QUEUE_LEAVEEMPTY;
2430 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
2431 leave_queue(qe);
2432 break;
2435 /* leave the queue if no reachable agents, if enabled */
2436 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
2437 *reason = QUEUE_LEAVEUNAVAIL;
2438 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
2439 leave_queue(qe);
2440 break;
2443 /* Make a position announcement, if enabled */
2444 if (qe->parent->announcefrequency && !ringing &&
2445 (res = say_position(qe)))
2446 break;
2448 /* Make a periodic announcement, if enabled */
2449 if (qe->parent->periodicannouncefrequency && !ringing &&
2450 (res = say_periodic_announcement(qe)))
2451 break;
2453 /* Wait a second before checking again */
2454 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
2455 if (res > 0 && !valid_exit(qe, res))
2456 res = 0;
2457 else
2458 break;
2462 return res;
2465 static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl)
2467 ast_mutex_lock(&q->lock);
2468 time(&member->lastcall);
2469 member->calls++;
2470 q->callscompleted++;
2471 if (callcompletedinsl)
2472 q->callscompletedinsl++;
2473 ast_mutex_unlock(&q->lock);
2474 return 0;
2477 /*! \brief Calculate the metric of each member in the outgoing callattempts
2479 * A numeric metric is given to each member depending on the ring strategy used
2480 * by the queue. Members with lower metrics will be called before members with
2481 * higher metrics
2483 static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
2485 if (qe->max_penalty && (mem->penalty > qe->max_penalty))
2486 return -1;
2488 switch (q->strategy) {
2489 case QUEUE_STRATEGY_RINGALL:
2490 /* Everyone equal, except for penalty */
2491 tmp->metric = mem->penalty * 1000000;
2492 break;
2493 case QUEUE_STRATEGY_ROUNDROBIN:
2494 if (!pos) {
2495 if (!q->wrapped) {
2496 /* No more channels, start over */
2497 q->rrpos = 0;
2498 } else {
2499 /* Prioritize next entry */
2500 q->rrpos++;
2502 q->wrapped = 0;
2504 /* Fall through */
2505 case QUEUE_STRATEGY_RRMEMORY:
2506 if (pos < q->rrpos) {
2507 tmp->metric = 1000 + pos;
2508 } else {
2509 if (pos > q->rrpos)
2510 /* Indicate there is another priority */
2511 q->wrapped = 1;
2512 tmp->metric = pos;
2514 tmp->metric += mem->penalty * 1000000;
2515 break;
2516 case QUEUE_STRATEGY_RANDOM:
2517 tmp->metric = ast_random() % 1000;
2518 tmp->metric += mem->penalty * 1000000;
2519 break;
2520 case QUEUE_STRATEGY_FEWESTCALLS:
2521 tmp->metric = mem->calls;
2522 tmp->metric += mem->penalty * 1000000;
2523 break;
2524 case QUEUE_STRATEGY_LEASTRECENT:
2525 if (!mem->lastcall)
2526 tmp->metric = 0;
2527 else
2528 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
2529 tmp->metric += mem->penalty * 1000000;
2530 break;
2531 default:
2532 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
2533 break;
2535 return 0;
2537 /*! \brief A large function which calls members, updates statistics, and bridges the caller and a member
2539 * Here is the process of this function
2540 * 1. Process any options passed to the Queue() application. Options here mean the third argument to Queue()
2541 * 2. Iterate trough the members of the queue, creating a callattempt corresponding to each member. During this
2542 * iteration, we also check the dialed_interfaces datastore to see if we have already attempted calling this
2543 * member. If we have, we do not create a callattempt. This is in place to prevent call forwarding loops. Also
2544 * during each iteration, we call calc_metric to determine which members should be rung when.
2545 * 3. Call ring_one to place a call to the appropriate member(s)
2546 * 4. Call wait_for_answer to wait for an answer. If no one answers, return.
2547 * 5. Take care of any holdtime announcements, member delays, or other options which occur after a call has been answered.
2548 * 6. Start the monitor or mixmonitor if the option is set
2549 * 7. Remove the caller from the queue to allow other callers to advance
2550 * 8. Bridge the call.
2551 * 9. Do any post processing after the call has disconnected.
2553 * \param[in] qe the queue_ent structure which corresponds to the caller attempting to reach members
2554 * \param[in] options the options passed as the third parameter to the Queue() application
2555 * \param[in] url the url passed as the fourth parameter to the Queue() application
2556 * \param[in,out] tries the number of times we have tried calling queue members
2557 * \param[out] noption set if the call to Queue() has the 'n' option set.
2558 * \param[in] agi the agi passed as the fifth parameter to the Queue() application
2561 static int try_calling(struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *tries, int *noption, const char *agi)
2563 struct member *cur;
2564 struct callattempt *outgoing = NULL; /* the list of calls we are building */
2565 int to;
2566 char oldexten[AST_MAX_EXTENSION]="";
2567 char oldcontext[AST_MAX_CONTEXT]="";
2568 char queuename[256]="";
2569 struct ast_channel *peer;
2570 struct ast_channel *which;
2571 struct callattempt *lpeer;
2572 struct member *member;
2573 struct ast_app *app;
2574 int res = 0, bridge = 0;
2575 int numbusies = 0;
2576 int x=0;
2577 char *announce = NULL;
2578 char digit = 0;
2579 time_t callstart;
2580 time_t now = time(NULL);
2581 struct ast_bridge_config bridge_config;
2582 char nondataquality = 1;
2583 char *agiexec = NULL;
2584 int ret = 0;
2585 const char *monitorfilename;
2586 const char *monitor_exec;
2587 const char *monitor_options;
2588 char tmpid[256], tmpid2[256];
2589 char meid[1024], meid2[1024];
2590 char mixmonargs[1512];
2591 struct ast_app *mixmonapp = NULL;
2592 char *p;
2593 char vars[2048];
2594 int forwardsallowed = 1;
2595 int callcompletedinsl;
2596 struct ao2_iterator memi;
2597 struct ast_datastore *datastore;
2599 ast_channel_lock(qe->chan);
2600 datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL);
2601 ast_channel_unlock(qe->chan);
2603 memset(&bridge_config, 0, sizeof(bridge_config));
2604 time(&now);
2606 for (; options && *options; options++)
2607 switch (*options) {
2608 case 't':
2609 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
2610 break;
2611 case 'T':
2612 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
2613 break;
2614 case 'w':
2615 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
2616 break;
2617 case 'W':
2618 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
2619 break;
2620 case 'd':
2621 nondataquality = 0;
2622 break;
2623 case 'h':
2624 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
2625 break;
2626 case 'H':
2627 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
2628 break;
2629 case 'n':
2630 if (qe->parent->strategy == QUEUE_STRATEGY_ROUNDROBIN || qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY)
2631 (*tries)++;
2632 else
2633 *tries = qe->parent->membercount;
2634 *noption = 1;
2635 break;
2636 case 'i':
2637 forwardsallowed = 0;
2638 break;
2641 /* Hold the lock while we setup the outgoing calls */
2642 if (use_weight)
2643 AST_LIST_LOCK(&queues);
2644 ast_mutex_lock(&qe->parent->lock);
2645 if (option_debug)
2646 ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n",
2647 qe->chan->name);
2648 ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
2649 if (!ast_strlen_zero(qe->announce))
2650 announce = qe->announce;
2651 if (!ast_strlen_zero(announceoverride))
2652 announce = announceoverride;
2654 memi = ao2_iterator_init(qe->parent->members, 0);
2655 while ((cur = ao2_iterator_next(&memi))) {
2656 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
2657 struct ast_dialed_interface *di;
2658 AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces;
2659 if (!tmp) {
2660 ao2_ref(cur, -1);
2661 ast_mutex_unlock(&qe->parent->lock);
2662 if (use_weight)
2663 AST_LIST_UNLOCK(&queues);
2664 goto out;
2666 if (!datastore) {
2667 if (!(datastore = ast_channel_datastore_alloc(&dialed_interface_info, NULL))) {
2668 ao2_ref(cur, -1);
2669 ast_mutex_unlock(&qe->parent->lock);
2670 if (use_weight)
2671 AST_LIST_UNLOCK(&queues);
2672 free(tmp);
2673 goto out;
2675 datastore->inheritance = DATASTORE_INHERIT_FOREVER;
2676 if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) {
2677 ao2_ref(cur, -1);
2678 ast_mutex_unlock(&qe->parent->lock);
2679 if (use_weight)
2680 AST_LIST_UNLOCK(&queues);
2681 free(tmp);
2682 goto out;
2684 datastore->data = dialed_interfaces;
2685 AST_LIST_HEAD_INIT(dialed_interfaces);
2687 ast_channel_lock(qe->chan);
2688 ast_channel_datastore_add(qe->chan, datastore);
2689 ast_channel_unlock(qe->chan);
2690 } else
2691 dialed_interfaces = datastore->data;
2693 AST_LIST_LOCK(dialed_interfaces);
2694 AST_LIST_TRAVERSE(dialed_interfaces, di, list) {
2695 if (!strcasecmp(cur->interface, di->interface)) {
2696 ast_log(LOG_DEBUG, "Skipping dialing interface '%s' since it has already been dialed\n",
2697 di->interface);
2698 break;
2701 AST_LIST_UNLOCK(dialed_interfaces);
2703 if (di) {
2704 free(tmp);
2705 continue;
2708 /* It is always ok to dial a Local interface. We only keep track of
2709 * which "real" interfaces have been dialed. The Local channel will
2710 * inherit this list so that if it ends up dialing a real interface,
2711 * it won't call one that has already been called. */
2712 if (strncasecmp(cur->interface, "Local/", 6)) {
2713 if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) {
2714 ao2_ref(cur, -1);
2715 ast_mutex_unlock(&qe->parent->lock);
2716 if (use_weight)
2717 AST_LIST_UNLOCK(&queues);
2718 free(tmp);
2719 goto out;
2721 strcpy(di->interface, cur->interface);
2723 AST_LIST_LOCK(dialed_interfaces);
2724 AST_LIST_INSERT_TAIL(dialed_interfaces, di, list);
2725 AST_LIST_UNLOCK(dialed_interfaces);
2728 tmp->stillgoing = -1;
2729 tmp->member = cur;
2730 tmp->oldstatus = cur->status;
2731 tmp->lastcall = cur->lastcall;
2732 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
2733 /* Special case: If we ring everyone, go ahead and ring them, otherwise
2734 just calculate their metric for the appropriate strategy */
2735 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
2736 /* Put them in the list of outgoing thingies... We're ready now.
2737 XXX If we're forcibly removed, these outgoing calls won't get
2738 hung up XXX */
2739 tmp->q_next = outgoing;
2740 outgoing = tmp;
2741 /* If this line is up, don't try anybody else */
2742 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
2743 break;
2744 } else {
2745 ao2_ref(cur, -1);
2746 free(tmp);
2749 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout))
2750 to = (qe->expire - now) * 1000;
2751 else
2752 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
2753 ++qe->pending;
2754 ast_mutex_unlock(&qe->parent->lock);
2755 ring_one(qe, outgoing, &numbusies);
2756 if (use_weight)
2757 AST_LIST_UNLOCK(&queues);
2758 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed);
2759 /* The ast_channel_datastore_remove() function could fail here if the
2760 * datastore was moved to another channel during a masquerade. If this is
2761 * the case, don't free the datastore here because later, when the channel
2762 * to which the datastore was moved hangs up, it will attempt to free this
2763 * datastore again, causing a crash
2765 if (datastore && !ast_channel_datastore_remove(qe->chan, datastore)) {
2766 ast_channel_datastore_free(datastore);
2768 ast_mutex_lock(&qe->parent->lock);
2769 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
2770 store_next(qe, outgoing);
2772 ast_mutex_unlock(&qe->parent->lock);
2773 peer = lpeer ? lpeer->chan : NULL;
2774 if (!peer) {
2775 qe->pending = 0;
2776 if (to) {
2777 /* Must gotten hung up */
2778 res = -1;
2779 } else {
2780 /* User exited by pressing a digit */
2781 res = digit;
2783 if (option_debug && res == -1)
2784 ast_log(LOG_DEBUG, "%s: Nobody answered.\n", qe->chan->name);
2785 } else { /* peer is valid */
2786 /* Ah ha! Someone answered within the desired timeframe. Of course after this
2787 we will always return with -1 so that it is hung up properly after the
2788 conversation. */
2789 qe->handled++;
2790 if (!strcmp(qe->chan->tech->type, "Zap"))
2791 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2792 if (!strcmp(peer->tech->type, "Zap"))
2793 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2794 /* Update parameters for the queue */
2795 time(&now);
2796 recalc_holdtime(qe, (now - qe->start));
2797 ast_mutex_lock(&qe->parent->lock);
2798 callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel);
2799 ast_mutex_unlock(&qe->parent->lock);
2800 member = lpeer->member;
2801 /* Increment the refcount for this member, since we're going to be using it for awhile in here. */
2802 ao2_ref(member, 1);
2803 hangupcalls(outgoing, peer);
2804 outgoing = NULL;
2805 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
2806 int res2;
2808 res2 = ast_autoservice_start(qe->chan);
2809 if (!res2) {
2810 if (qe->parent->memberdelay) {
2811 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
2812 res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
2814 if (!res2 && announce) {
2815 play_file(peer, announce);
2817 if (!res2 && qe->parent->reportholdtime) {
2818 if (!play_file(peer, qe->parent->sound_reporthold)) {
2819 int holdtime;
2821 time(&now);
2822 holdtime = abs((now - qe->start) / 60);
2823 if (holdtime < 2) {
2824 play_file(peer, qe->parent->sound_lessthan);
2825 ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL);
2826 } else
2827 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
2828 play_file(peer, qe->parent->sound_minutes);
2832 res2 |= ast_autoservice_stop(qe->chan);
2833 if (peer->_softhangup) {
2834 /* Agent must have hung up */
2835 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", peer->name);
2836 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", "");
2837 record_abandoned(qe);
2838 if (qe->parent->eventwhencalled)
2839 manager_event(EVENT_FLAG_AGENT, "AgentDump",
2840 "Queue: %s\r\n"
2841 "Uniqueid: %s\r\n"
2842 "Channel: %s\r\n"
2843 "Member: %s\r\n"
2844 "MemberName: %s\r\n"
2845 "%s",
2846 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
2847 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
2848 ast_hangup(peer);
2849 ao2_ref(member, -1);
2850 goto out;
2851 } else if (res2) {
2852 /* Caller must have hung up just before being connected*/
2853 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
2854 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
2855 record_abandoned(qe);
2856 ast_hangup(peer);
2857 ao2_ref(member, -1);
2858 return -1;
2861 /* Stop music on hold */
2862 ast_moh_stop(qe->chan);
2863 /* If appropriate, log that we have a destination channel */
2864 if (qe->chan->cdr)
2865 ast_cdr_setdestchan(qe->chan->cdr, peer->name);
2866 /* Make sure channels are compatible */
2867 res = ast_channel_make_compatible(qe->chan, peer);
2868 if (res < 0) {
2869 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", "");
2870 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
2871 record_abandoned(qe);
2872 ast_hangup(peer);
2873 ao2_ref(member, -1);
2874 return -1;
2877 if (qe->parent->setinterfacevar)
2878 pbx_builtin_setvar_helper(qe->chan, "MEMBERINTERFACE", member->interface);
2880 /* Begin Monitoring */
2881 if (qe->parent->monfmt && *qe->parent->monfmt) {
2882 if (!qe->parent->montype) {
2883 if (option_debug)
2884 ast_log(LOG_DEBUG, "Starting Monitor as requested.\n");
2885 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
2886 if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))
2887 which = qe->chan;
2888 else
2889 which = peer;
2890 if (monitorfilename)
2891 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 );
2892 else if (qe->chan->cdr)
2893 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
2894 else {
2895 /* Last ditch effort -- no CDR, make up something */
2896 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
2897 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 );
2899 if (qe->parent->monjoin)
2900 ast_monitor_setjoinfiles(which, 1);
2901 } else {
2902 if (option_debug)
2903 ast_log(LOG_DEBUG, "Starting MixMonitor as requested.\n");
2904 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
2905 if (!monitorfilename) {
2906 if (qe->chan->cdr)
2907 ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid)-1);
2908 else
2909 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
2910 } else {
2911 ast_copy_string(tmpid2, monitorfilename, sizeof(tmpid2)-1);
2912 for (p = tmpid2; *p ; p++) {
2913 if (*p == '^' && *(p+1) == '{') {
2914 *p = '$';
2918 memset(tmpid, 0, sizeof(tmpid));
2919 pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1);
2922 monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC");
2923 monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS");
2925 if (monitor_exec) {
2926 ast_copy_string(meid2, monitor_exec, sizeof(meid2)-1);
2927 for (p = meid2; *p ; p++) {
2928 if (*p == '^' && *(p+1) == '{') {
2929 *p = '$';
2933 memset(meid, 0, sizeof(meid));
2934 pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1);
2937 snprintf(tmpid2, sizeof(tmpid2)-1, "%s.%s", tmpid, qe->parent->monfmt);
2939 mixmonapp = pbx_findapp("MixMonitor");
2941 if (strchr(tmpid2, '|')) {
2942 ast_log(LOG_WARNING, "monitor-format (in queues.conf) and MONITOR_FILENAME cannot contain a '|'! Not recording.\n");
2943 mixmonapp = NULL;
2946 if (!monitor_options)
2947 monitor_options = "";
2949 if (strchr(monitor_options, '|')) {
2950 ast_log(LOG_WARNING, "MONITOR_OPTIONS cannot contain a '|'! Not recording.\n");
2951 mixmonapp = NULL;
2954 if (mixmonapp) {
2955 if (!ast_strlen_zero(monitor_exec))
2956 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s|%s", tmpid2, monitor_options, monitor_exec);
2957 else
2958 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s", tmpid2, monitor_options);
2960 if (option_debug)
2961 ast_log(LOG_DEBUG, "Arguments being passed to MixMonitor: %s\n", mixmonargs);
2962 /* We purposely lock the CDR so that pbx_exec does not update the application data */
2963 if (qe->chan->cdr)
2964 ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
2965 ret = pbx_exec(qe->chan, mixmonapp, mixmonargs);
2966 if (qe->chan->cdr)
2967 ast_clear_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
2969 } else
2970 ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n");
2974 /* Drop out of the queue at this point, to prepare for next caller */
2975 leave_queue(qe);
2976 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
2977 if (option_debug)
2978 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
2979 ast_channel_sendurl(peer, url);
2981 if (!ast_strlen_zero(agi)) {
2982 if (option_debug)
2983 ast_log(LOG_DEBUG, "app_queue: agi=%s.\n", agi);
2984 app = pbx_findapp("agi");
2985 if (app) {
2986 agiexec = ast_strdupa(agi);
2987 ret = pbx_exec(qe->chan, app, agiexec);
2988 } else
2989 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
2991 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s", (long)time(NULL) - qe->start, peer->uniqueid);
2992 if (qe->parent->eventwhencalled)
2993 manager_event(EVENT_FLAG_AGENT, "AgentConnect",
2994 "Queue: %s\r\n"
2995 "Uniqueid: %s\r\n"
2996 "Channel: %s\r\n"
2997 "Member: %s\r\n"
2998 "MemberName: %s\r\n"
2999 "Holdtime: %ld\r\n"
3000 "BridgedChannel: %s\r\n"
3001 "%s",
3002 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
3003 (long)time(NULL) - qe->start, peer->uniqueid,
3004 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
3005 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
3006 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
3007 time(&callstart);
3009 if (member->status == AST_DEVICE_NOT_INUSE)
3010 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);
3013 bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
3015 if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
3016 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld",
3017 qe->chan->exten, qe->chan->context, (long) (callstart - qe->start),
3018 (long) (time(NULL) - callstart));
3019 } else if (qe->chan->_softhangup) {
3020 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d",
3021 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
3022 if (qe->parent->eventwhencalled)
3023 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
3024 "Queue: %s\r\n"
3025 "Uniqueid: %s\r\n"
3026 "Channel: %s\r\n"
3027 "Member: %s\r\n"
3028 "MemberName: %s\r\n"
3029 "HoldTime: %ld\r\n"
3030 "TalkTime: %ld\r\n"
3031 "Reason: caller\r\n"
3032 "%s",
3033 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
3034 (long)(callstart - qe->start), (long)(time(NULL) - callstart),
3035 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
3036 } else {
3037 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d",
3038 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
3039 if (qe->parent->eventwhencalled)
3040 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
3041 "Queue: %s\r\n"
3042 "Uniqueid: %s\r\n"
3043 "Channel: %s\r\n"
3044 "MemberName: %s\r\n"
3045 "HoldTime: %ld\r\n"
3046 "TalkTime: %ld\r\n"
3047 "Reason: agent\r\n"
3048 "%s",
3049 queuename, qe->chan->uniqueid, peer->name, member->membername, (long)(callstart - qe->start),
3050 (long)(time(NULL) - callstart),
3051 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
3054 if (bridge != AST_PBX_NO_HANGUP_PEER)
3055 ast_hangup(peer);
3056 update_queue(qe->parent, member, callcompletedinsl);
3057 res = bridge ? bridge : 1;
3058 ao2_ref(member, -1);
3060 out:
3061 hangupcalls(outgoing, NULL);
3063 return res;
3066 static int wait_a_bit(struct queue_ent *qe)
3068 /* Don't need to hold the lock while we setup the outgoing calls */
3069 int retrywait = qe->parent->retry * 1000;
3071 int res = ast_waitfordigit(qe->chan, retrywait);
3072 if (res > 0 && !valid_exit(qe, res))
3073 res = 0;
3075 return res;
3078 static struct member *interface_exists(struct call_queue *q, const char *interface)
3080 struct member *mem;
3081 struct ao2_iterator mem_iter;
3083 if (!q)
3084 return NULL;
3086 mem_iter = ao2_iterator_init(q->members, 0);
3087 while ((mem = ao2_iterator_next(&mem_iter))) {
3088 if (!strcasecmp(interface, mem->interface))
3089 return mem;
3090 ao2_ref(mem, -1);
3093 return NULL;
3097 /* Dump all members in a specific queue to the database
3099 * <pm_family>/<queuename> = <interface>;<penalty>;<paused>[|...]
3102 static void dump_queue_members(struct call_queue *pm_queue)
3104 struct member *cur_member;
3105 char value[PM_MAX_LEN];
3106 int value_len = 0;
3107 int res;
3108 struct ao2_iterator mem_iter;
3110 memset(value, 0, sizeof(value));
3112 if (!pm_queue)
3113 return;
3115 mem_iter = ao2_iterator_init(pm_queue->members, 0);
3116 while ((cur_member = ao2_iterator_next(&mem_iter))) {
3117 if (!cur_member->dynamic) {
3118 ao2_ref(cur_member, -1);
3119 continue;
3122 res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s",
3123 value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername);
3125 ao2_ref(cur_member, -1);
3127 if (res != strlen(value + value_len)) {
3128 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
3129 break;
3131 value_len += res;
3134 if (value_len && !cur_member) {
3135 if (ast_db_put(pm_family, pm_queue->name, value))
3136 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
3137 } else
3138 /* Delete the entry if the queue is empty or there is an error */
3139 ast_db_del(pm_family, pm_queue->name);
3142 static int remove_from_queue(const char *queuename, const char *interface)
3144 struct call_queue *q;
3145 struct member *mem, tmpmem;
3146 int res = RES_NOSUCHQUEUE;
3148 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
3150 AST_LIST_LOCK(&queues);
3151 AST_LIST_TRAVERSE(&queues, q, list) {
3152 ast_mutex_lock(&q->lock);
3153 if (strcmp(q->name, queuename)) {
3154 ast_mutex_unlock(&q->lock);
3155 continue;
3158 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
3159 /* XXX future changes should beware of this assumption!! */
3160 if (!mem->dynamic) {
3161 res = RES_NOT_DYNAMIC;
3162 ao2_ref(mem, -1);
3163 ast_mutex_unlock(&q->lock);
3164 break;
3166 q->membercount--;
3167 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
3168 "Queue: %s\r\n"
3169 "Location: %s\r\n"
3170 "MemberName: %s\r\n",
3171 q->name, mem->interface, mem->membername);
3172 ao2_unlink(q->members, mem);
3173 ao2_ref(mem, -1);
3175 if (queue_persistent_members)
3176 dump_queue_members(q);
3178 res = RES_OKAY;
3179 } else {
3180 res = RES_EXISTS;
3182 ast_mutex_unlock(&q->lock);
3183 break;
3186 if (res == RES_OKAY)
3187 remove_from_interfaces(interface);
3189 AST_LIST_UNLOCK(&queues);
3191 return res;
3195 static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump)
3197 struct call_queue *q;
3198 struct member *new_member, *old_member;
3199 int res = RES_NOSUCHQUEUE;
3201 /* \note Ensure the appropriate realtime queue is loaded. Note that this
3202 * short-circuits if the queue is already in memory. */
3203 if (!(q = load_realtime_queue(queuename)))
3204 return res;
3206 AST_LIST_LOCK(&queues);
3208 ast_mutex_lock(&q->lock);
3209 if ((old_member = interface_exists(q, interface)) == NULL) {
3210 add_to_interfaces(interface);
3211 if ((new_member = create_queue_member(interface, membername, penalty, paused))) {
3212 new_member->dynamic = 1;
3213 ao2_link(q->members, new_member);
3214 q->membercount++;
3215 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
3216 "Queue: %s\r\n"
3217 "Location: %s\r\n"
3218 "MemberName: %s\r\n"
3219 "Membership: %s\r\n"
3220 "Penalty: %d\r\n"
3221 "CallsTaken: %d\r\n"
3222 "LastCall: %d\r\n"
3223 "Status: %d\r\n"
3224 "Paused: %d\r\n",
3225 q->name, new_member->interface, new_member->membername,
3226 "dynamic",
3227 new_member->penalty, new_member->calls, (int) new_member->lastcall,
3228 new_member->status, new_member->paused);
3230 ao2_ref(new_member, -1);
3231 new_member = NULL;
3233 if (dump)
3234 dump_queue_members(q);
3236 res = RES_OKAY;
3237 } else {
3238 res = RES_OUTOFMEMORY;
3240 } else {
3241 ao2_ref(old_member, -1);
3242 res = RES_EXISTS;
3244 ast_mutex_unlock(&q->lock);
3245 AST_LIST_UNLOCK(&queues);
3247 return res;
3250 static int set_member_paused(const char *queuename, const char *interface, int paused)
3252 int found = 0;
3253 struct call_queue *q;
3254 struct member *mem;
3256 /* Special event for when all queues are paused - individual events still generated */
3257 /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */
3258 if (ast_strlen_zero(queuename))
3259 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
3261 AST_LIST_LOCK(&queues);
3262 AST_LIST_TRAVERSE(&queues, q, list) {
3263 ast_mutex_lock(&q->lock);
3264 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
3265 if ((mem = interface_exists(q, interface))) {
3266 found++;
3267 if (mem->paused == paused)
3268 ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
3269 mem->paused = paused;
3271 if (queue_persistent_members)
3272 dump_queue_members(q);
3274 if (mem->realtime)
3275 update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0");
3277 ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", "");
3279 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
3280 "Queue: %s\r\n"
3281 "Location: %s\r\n"
3282 "MemberName: %s\r\n"
3283 "Paused: %d\r\n",
3284 q->name, mem->interface, mem->membername, paused);
3285 ao2_ref(mem, -1);
3288 ast_mutex_unlock(&q->lock);
3290 AST_LIST_UNLOCK(&queues);
3292 return found ? RESULT_SUCCESS : RESULT_FAILURE;
3295 /* Reload dynamic queue members persisted into the astdb */
3296 static void reload_queue_members(void)
3298 char *cur_ptr;
3299 char *queue_name;
3300 char *member;
3301 char *interface;
3302 char *membername = NULL;
3303 char *penalty_tok;
3304 int penalty = 0;
3305 char *paused_tok;
3306 int paused = 0;
3307 struct ast_db_entry *db_tree;
3308 struct ast_db_entry *entry;
3309 struct call_queue *cur_queue;
3310 char queue_data[PM_MAX_LEN];
3312 AST_LIST_LOCK(&queues);
3314 /* Each key in 'pm_family' is the name of a queue */
3315 db_tree = ast_db_gettree(pm_family, NULL);
3316 for (entry = db_tree; entry; entry = entry->next) {
3318 queue_name = entry->key + strlen(pm_family) + 2;
3320 AST_LIST_TRAVERSE(&queues, cur_queue, list) {
3321 ast_mutex_lock(&cur_queue->lock);
3322 if (!strcmp(queue_name, cur_queue->name))
3323 break;
3324 ast_mutex_unlock(&cur_queue->lock);
3327 if (!cur_queue)
3328 cur_queue = load_realtime_queue(queue_name);
3330 if (!cur_queue) {
3331 /* If the queue no longer exists, remove it from the
3332 * database */
3333 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
3334 ast_db_del(pm_family, queue_name);
3335 continue;
3336 } else
3337 ast_mutex_unlock(&cur_queue->lock);
3339 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN))
3340 continue;
3342 cur_ptr = queue_data;
3343 while ((member = strsep(&cur_ptr, "|"))) {
3344 if (ast_strlen_zero(member))
3345 continue;
3347 interface = strsep(&member, ";");
3348 penalty_tok = strsep(&member, ";");
3349 paused_tok = strsep(&member, ";");
3350 membername = strsep(&member, ";");
3352 if (!penalty_tok) {
3353 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
3354 break;
3356 penalty = strtol(penalty_tok, NULL, 10);
3357 if (errno == ERANGE) {
3358 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
3359 break;
3362 if (!paused_tok) {
3363 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
3364 break;
3366 paused = strtol(paused_tok, NULL, 10);
3367 if ((errno == ERANGE) || paused < 0 || paused > 1) {
3368 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
3369 break;
3371 if (ast_strlen_zero(membername))
3372 membername = interface;
3374 if (option_debug)
3375 ast_log(LOG_DEBUG, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name, interface, membername, penalty, paused);
3377 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0) == RES_OUTOFMEMORY) {
3378 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
3379 break;
3384 AST_LIST_UNLOCK(&queues);
3385 if (db_tree) {
3386 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
3387 ast_db_freetree(db_tree);
3391 static int pqm_exec(struct ast_channel *chan, void *data)
3393 struct ast_module_user *lu;
3394 char *parse;
3395 int priority_jump = 0;
3396 AST_DECLARE_APP_ARGS(args,
3397 AST_APP_ARG(queuename);
3398 AST_APP_ARG(interface);
3399 AST_APP_ARG(options);
3402 if (ast_strlen_zero(data)) {
3403 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface[|options])\n");
3404 return -1;
3407 parse = ast_strdupa(data);
3409 AST_STANDARD_APP_ARGS(args, parse);
3411 lu = ast_module_user_add(chan);
3413 if (args.options) {
3414 if (strchr(args.options, 'j'))
3415 priority_jump = 1;
3418 if (ast_strlen_zero(args.interface)) {
3419 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
3420 ast_module_user_remove(lu);
3421 return -1;
3424 if (set_member_paused(args.queuename, args.interface, 1)) {
3425 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
3426 if (priority_jump || ast_opt_priority_jumping) {
3427 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
3428 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
3429 ast_module_user_remove(lu);
3430 return 0;
3433 ast_module_user_remove(lu);
3434 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
3435 return 0;
3438 ast_module_user_remove(lu);
3439 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
3441 return 0;
3444 static int upqm_exec(struct ast_channel *chan, void *data)
3446 struct ast_module_user *lu;
3447 char *parse;
3448 int priority_jump = 0;
3449 AST_DECLARE_APP_ARGS(args,
3450 AST_APP_ARG(queuename);
3451 AST_APP_ARG(interface);
3452 AST_APP_ARG(options);
3455 if (ast_strlen_zero(data)) {
3456 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface[|options])\n");
3457 return -1;
3460 parse = ast_strdupa(data);
3462 AST_STANDARD_APP_ARGS(args, parse);
3464 lu = ast_module_user_add(chan);
3466 if (args.options) {
3467 if (strchr(args.options, 'j'))
3468 priority_jump = 1;
3471 if (ast_strlen_zero(args.interface)) {
3472 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
3473 ast_module_user_remove(lu);
3474 return -1;
3477 if (set_member_paused(args.queuename, args.interface, 0)) {
3478 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
3479 if (priority_jump || ast_opt_priority_jumping) {
3480 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
3481 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
3482 ast_module_user_remove(lu);
3483 return 0;
3486 ast_module_user_remove(lu);
3487 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
3488 return 0;
3491 ast_module_user_remove(lu);
3492 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
3494 return 0;
3497 static int rqm_exec(struct ast_channel *chan, void *data)
3499 int res=-1;
3500 struct ast_module_user *lu;
3501 char *parse, *temppos = NULL;
3502 int priority_jump = 0;
3503 AST_DECLARE_APP_ARGS(args,
3504 AST_APP_ARG(queuename);
3505 AST_APP_ARG(interface);
3506 AST_APP_ARG(options);
3510 if (ast_strlen_zero(data)) {
3511 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n");
3512 return -1;
3515 parse = ast_strdupa(data);
3517 AST_STANDARD_APP_ARGS(args, parse);
3519 lu = ast_module_user_add(chan);
3521 if (ast_strlen_zero(args.interface)) {
3522 args.interface = ast_strdupa(chan->name);
3523 temppos = strrchr(args.interface, '-');
3524 if (temppos)
3525 *temppos = '\0';
3528 if (args.options) {
3529 if (strchr(args.options, 'j'))
3530 priority_jump = 1;
3533 switch (remove_from_queue(args.queuename, args.interface)) {
3534 case RES_OKAY:
3535 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", "");
3536 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
3537 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
3538 res = 0;
3539 break;
3540 case RES_EXISTS:
3541 ast_log(LOG_DEBUG, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
3542 if (priority_jump || ast_opt_priority_jumping)
3543 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
3544 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
3545 res = 0;
3546 break;
3547 case RES_NOSUCHQUEUE:
3548 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
3549 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
3550 res = 0;
3551 break;
3552 case RES_NOT_DYNAMIC:
3553 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface);
3554 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC");
3555 res = 0;
3556 break;
3559 ast_module_user_remove(lu);
3561 return res;
3564 static int aqm_exec(struct ast_channel *chan, void *data)
3566 int res=-1;
3567 struct ast_module_user *lu;
3568 char *parse, *temppos = NULL;
3569 int priority_jump = 0;
3570 AST_DECLARE_APP_ARGS(args,
3571 AST_APP_ARG(queuename);
3572 AST_APP_ARG(interface);
3573 AST_APP_ARG(penalty);
3574 AST_APP_ARG(options);
3575 AST_APP_ARG(membername);
3577 int penalty = 0;
3579 if (ast_strlen_zero(data)) {
3580 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface]|[penalty][|options][|membername]])\n");
3581 return -1;
3584 parse = ast_strdupa(data);
3586 AST_STANDARD_APP_ARGS(args, parse);
3588 lu = ast_module_user_add(chan);
3590 if (ast_strlen_zero(args.interface)) {
3591 args.interface = ast_strdupa(chan->name);
3592 temppos = strrchr(args.interface, '-');
3593 if (temppos)
3594 *temppos = '\0';
3597 if (!ast_strlen_zero(args.penalty)) {
3598 if ((sscanf(args.penalty, "%d", &penalty) != 1) || penalty < 0) {
3599 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
3600 penalty = 0;
3604 if (args.options) {
3605 if (strchr(args.options, 'j'))
3606 priority_jump = 1;
3609 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members)) {
3610 case RES_OKAY:
3611 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", "");
3612 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
3613 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
3614 res = 0;
3615 break;
3616 case RES_EXISTS:
3617 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
3618 if (priority_jump || ast_opt_priority_jumping)
3619 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
3620 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
3621 res = 0;
3622 break;
3623 case RES_NOSUCHQUEUE:
3624 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
3625 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
3626 res = 0;
3627 break;
3628 case RES_OUTOFMEMORY:
3629 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename);
3630 break;
3633 ast_module_user_remove(lu);
3635 return res;
3638 static int ql_exec(struct ast_channel *chan, void *data)
3640 struct ast_module_user *u;
3641 char *parse;
3643 AST_DECLARE_APP_ARGS(args,
3644 AST_APP_ARG(queuename);
3645 AST_APP_ARG(uniqueid);
3646 AST_APP_ARG(membername);
3647 AST_APP_ARG(event);
3648 AST_APP_ARG(params);
3651 if (ast_strlen_zero(data)) {
3652 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo]\n");
3653 return -1;
3656 u = ast_module_user_add(chan);
3658 parse = ast_strdupa(data);
3660 AST_STANDARD_APP_ARGS(args, parse);
3662 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
3663 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
3664 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo])\n");
3665 ast_module_user_remove(u);
3666 return -1;
3669 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event,
3670 "%s", args.params ? args.params : "");
3672 ast_module_user_remove(u);
3674 return 0;
3677 /*!\brief The starting point for all queue calls
3679 * The process involved here is to
3680 * 1. Parse the options specified in the call to Queue()
3681 * 2. Join the queue
3682 * 3. Wait in a loop until it is our turn to try calling a queue member
3683 * 4. Attempt to call a queue member
3684 * 5. If 4. did not result in a bridged call, then check for between
3685 * call options such as periodic announcements etc.
3686 * 6. Try 4 again uless some condition (such as an expiration time) causes us to
3687 * exit the queue.
3689 static int queue_exec(struct ast_channel *chan, void *data)
3691 int res=-1;
3692 int ringing=0;
3693 struct ast_module_user *lu;
3694 const char *user_priority;
3695 const char *max_penalty_str;
3696 int prio;
3697 int max_penalty;
3698 enum queue_result reason = QUEUE_UNKNOWN;
3699 /* whether to exit Queue application after the timeout hits */
3700 int tries = 0;
3701 int noption = 0;
3702 char *parse;
3703 AST_DECLARE_APP_ARGS(args,
3704 AST_APP_ARG(queuename);
3705 AST_APP_ARG(options);
3706 AST_APP_ARG(url);
3707 AST_APP_ARG(announceoverride);
3708 AST_APP_ARG(queuetimeoutstr);
3709 AST_APP_ARG(agi);
3711 /* Our queue entry */
3712 struct queue_ent qe;
3714 if (ast_strlen_zero(data)) {
3715 ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL[|announceoverride[|timeout[|agi]]]]]\n");
3716 return -1;
3719 parse = ast_strdupa(data);
3720 AST_STANDARD_APP_ARGS(args, parse);
3722 lu = ast_module_user_add(chan);
3724 /* Setup our queue entry */
3725 memset(&qe, 0, sizeof(qe));
3726 qe.start = time(NULL);
3728 /* set the expire time based on the supplied timeout; */
3729 if (!ast_strlen_zero(args.queuetimeoutstr))
3730 qe.expire = qe.start + atoi(args.queuetimeoutstr);
3731 else
3732 qe.expire = 0;
3734 /* Get the priority from the variable ${QUEUE_PRIO} */
3735 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
3736 if (user_priority) {
3737 if (sscanf(user_priority, "%d", &prio) == 1) {
3738 if (option_debug)
3739 ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
3740 chan->name, prio);
3741 } else {
3742 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
3743 user_priority, chan->name);
3744 prio = 0;
3746 } else {
3747 if (option_debug > 2)
3748 ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n");
3749 prio = 0;
3752 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
3753 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
3754 if (sscanf(max_penalty_str, "%d", &max_penalty) == 1) {
3755 if (option_debug)
3756 ast_log(LOG_DEBUG, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n",
3757 chan->name, max_penalty);
3758 } else {
3759 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
3760 max_penalty_str, chan->name);
3761 max_penalty = 0;
3763 } else {
3764 max_penalty = 0;
3767 if (args.options && (strchr(args.options, 'r')))
3768 ringing = 1;
3770 if (option_debug)
3771 ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
3772 args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio);
3774 qe.chan = chan;
3775 qe.prio = prio;
3776 qe.max_penalty = max_penalty;
3777 qe.last_pos_said = 0;
3778 qe.last_pos = 0;
3779 qe.last_periodic_announce_time = time(NULL);
3780 qe.last_periodic_announce_sound = 0;
3781 qe.valid_digits = 0;
3782 if (!join_queue(args.queuename, &qe, &reason)) {
3783 int makeannouncement = 0;
3785 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", S_OR(args.url, ""),
3786 S_OR(chan->cid.cid_num, ""));
3787 check_turns:
3788 if (ringing) {
3789 ast_indicate(chan, AST_CONTROL_RINGING);
3790 } else {
3791 ast_moh_start(chan, qe.moh, NULL);
3794 /* This is the wait loop for callers 2 through maxlen */
3795 res = wait_our_turn(&qe, ringing, &reason);
3796 if (res)
3797 goto stop;
3799 for (;;) {
3800 /* This is the wait loop for the head caller*/
3801 /* To exit, they may get their call answered; */
3802 /* they may dial a digit from the queue context; */
3803 /* or, they may timeout. */
3805 enum queue_member_status stat;
3807 /* Leave if we have exceeded our queuetimeout */
3808 if (qe.expire && (time(NULL) > qe.expire)) {
3809 record_abandoned(&qe);
3810 reason = QUEUE_TIMEOUT;
3811 res = 0;
3812 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
3813 break;
3816 if (makeannouncement) {
3817 /* Make a position announcement, if enabled */
3818 if (qe.parent->announcefrequency && !ringing)
3819 if ((res = say_position(&qe)))
3820 goto stop;
3823 makeannouncement = 1;
3825 /* Make a periodic announcement, if enabled */
3826 if (qe.parent->periodicannouncefrequency && !ringing)
3827 if ((res = say_periodic_announcement(&qe)))
3828 goto stop;
3830 /* Try calling all queue members for 'timeout' seconds */
3831 res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi);
3832 if (res)
3833 goto stop;
3835 stat = get_member_status(qe.parent, qe.max_penalty);
3837 /* exit after 'timeout' cycle if 'n' option enabled */
3838 if (noption && tries >= qe.parent->membercount) {
3839 if (option_verbose > 2)
3840 ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n");
3841 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
3842 record_abandoned(&qe);
3843 reason = QUEUE_TIMEOUT;
3844 res = 0;
3845 break;
3848 /* leave the queue if no agents, if enabled */
3849 if (qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
3850 record_abandoned(&qe);
3851 reason = QUEUE_LEAVEEMPTY;
3852 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
3853 res = 0;
3854 break;
3857 /* leave the queue if no reachable agents, if enabled */
3858 if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
3859 record_abandoned(&qe);
3860 reason = QUEUE_LEAVEUNAVAIL;
3861 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
3862 res = 0;
3863 break;
3866 /* Leave if we have exceeded our queuetimeout */
3867 if (qe.expire && (time(NULL) > qe.expire)) {
3868 record_abandoned(&qe);
3869 reason = QUEUE_TIMEOUT;
3870 res = 0;
3871 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
3872 break;
3875 /* If using dynamic realtime members, we should regenerate the member list for this queue */
3876 update_realtime_members(qe.parent);
3878 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
3879 res = wait_a_bit(&qe);
3880 if (res)
3881 goto stop;
3884 /* Since this is a priority queue and
3885 * it is not sure that we are still at the head
3886 * of the queue, go and check for our turn again.
3888 if (!is_our_turn(&qe)) {
3889 if (option_debug)
3890 ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n",
3891 qe.chan->name);
3892 goto check_turns;
3896 stop:
3897 if (res) {
3898 if (res < 0) {
3899 if (!qe.handled) {
3900 record_abandoned(&qe);
3901 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON",
3902 "%d|%d|%ld", qe.pos, qe.opos,
3903 (long) time(NULL) - qe.start);
3905 res = -1;
3906 } else if (qe.valid_digits) {
3907 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY",
3908 "%s|%d", qe.digits, qe.pos);
3912 /* Don't allow return code > 0 */
3913 if (res >= 0 && res != AST_PBX_KEEPALIVE) {
3914 res = 0;
3915 if (ringing) {
3916 ast_indicate(chan, -1);
3917 } else {
3918 ast_moh_stop(chan);
3920 ast_stopstream(chan);
3922 leave_queue(&qe);
3923 if (reason != QUEUE_UNKNOWN)
3924 set_queue_result(chan, reason);
3925 } else {
3926 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
3927 set_queue_result(chan, reason);
3928 res = 0;
3930 ast_module_user_remove(lu);
3932 return res;
3935 static int queue_function_qac(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
3937 int count = 0;
3938 struct call_queue *q;
3939 struct ast_module_user *lu;
3940 struct member *m;
3941 struct ao2_iterator mem_iter;
3943 buf[0] = '\0';
3945 if (ast_strlen_zero(data)) {
3946 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
3947 return -1;
3950 lu = ast_module_user_add(chan);
3952 if ((q = load_realtime_queue(data))) {
3953 ast_mutex_lock(&q->lock);
3954 mem_iter = ao2_iterator_init(q->members, 0);
3955 while ((m = ao2_iterator_next(&mem_iter))) {
3956 /* Count the agents who are logged in and presently answering calls */
3957 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
3958 count++;
3960 ao2_ref(m, -1);
3962 ast_mutex_unlock(&q->lock);
3963 } else
3964 ast_log(LOG_WARNING, "queue %s was not found\n", data);
3966 snprintf(buf, len, "%d", count);
3967 ast_module_user_remove(lu);
3969 return 0;
3972 static int queue_function_queuewaitingcount(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
3974 int count = 0;
3975 struct call_queue *q;
3976 struct ast_module_user *lu;
3977 struct ast_variable *var = NULL;
3979 buf[0] = '\0';
3981 if (ast_strlen_zero(data)) {
3982 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
3983 return -1;
3986 lu = ast_module_user_add(chan);
3988 AST_LIST_LOCK(&queues);
3989 AST_LIST_TRAVERSE(&queues, q, list) {
3990 if (!strcasecmp(q->name, data)) {
3991 ast_mutex_lock(&q->lock);
3992 break;
3995 AST_LIST_UNLOCK(&queues);
3997 if (q) {
3998 count = q->count;
3999 ast_mutex_unlock(&q->lock);
4000 } else if ((var = ast_load_realtime("queues", "name", data, NULL))) {
4001 /* if the queue is realtime but was not found in memory, this
4002 * means that the queue had been deleted from memory since it was
4003 * "dead." This means it has a 0 waiting count
4005 count = 0;
4006 ast_variables_destroy(var);
4007 } else
4008 ast_log(LOG_WARNING, "queue %s was not found\n", data);
4010 snprintf(buf, len, "%d", count);
4011 ast_module_user_remove(lu);
4012 return 0;
4015 static int queue_function_queuememberlist(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
4017 struct ast_module_user *u;
4018 struct call_queue *q;
4019 struct member *m;
4021 /* Ensure an otherwise empty list doesn't return garbage */
4022 buf[0] = '\0';
4024 if (ast_strlen_zero(data)) {
4025 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
4026 return -1;
4029 u = ast_module_user_add(chan);
4031 AST_LIST_LOCK(&queues);
4032 AST_LIST_TRAVERSE(&queues, q, list) {
4033 if (!strcasecmp(q->name, data)) {
4034 ast_mutex_lock(&q->lock);
4035 break;
4038 AST_LIST_UNLOCK(&queues);
4040 if (q) {
4041 int buflen = 0, count = 0;
4042 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
4044 while ((m = ao2_iterator_next(&mem_iter))) {
4045 /* strcat() is always faster than printf() */
4046 if (count++) {
4047 strncat(buf + buflen, ",", len - buflen - 1);
4048 buflen++;
4050 strncat(buf + buflen, m->membername, len - buflen - 1);
4051 buflen += strlen(m->membername);
4052 /* Safeguard against overflow (negative length) */
4053 if (buflen >= len - 2) {
4054 ao2_ref(m, -1);
4055 ast_log(LOG_WARNING, "Truncating list\n");
4056 break;
4058 ao2_ref(m, -1);
4060 ast_mutex_unlock(&q->lock);
4061 } else
4062 ast_log(LOG_WARNING, "queue %s was not found\n", data);
4064 /* We should already be terminated, but let's make sure. */
4065 buf[len - 1] = '\0';
4066 ast_module_user_remove(u);
4068 return 0;
4071 static struct ast_custom_function queueagentcount_function = {
4072 .name = "QUEUEAGENTCOUNT",
4073 .synopsis = "Count number of agents answering a queue",
4074 .syntax = "QUEUEAGENTCOUNT(<queuename>)",
4075 .desc =
4076 "Returns the number of members currently associated with the specified queue.\n"
4077 "This function is deprecated. You should use QUEUE_MEMBER_COUNT() instead.\n",
4078 .read = queue_function_qac,
4081 static struct ast_custom_function queuemembercount_function = {
4082 .name = "QUEUE_MEMBER_COUNT",
4083 .synopsis = "Count number of members answering a queue",
4084 .syntax = "QUEUE_MEMBER_COUNT(<queuename>)",
4085 .desc =
4086 "Returns the number of members currently associated with the specified queue.\n",
4087 .read = queue_function_qac,
4090 static struct ast_custom_function queuewaitingcount_function = {
4091 .name = "QUEUE_WAITING_COUNT",
4092 .synopsis = "Count number of calls currently waiting in a queue",
4093 .syntax = "QUEUE_WAITING_COUNT(<queuename>)",
4094 .desc =
4095 "Returns the number of callers currently waiting in the specified queue.\n",
4096 .read = queue_function_queuewaitingcount,
4099 static struct ast_custom_function queuememberlist_function = {
4100 .name = "QUEUE_MEMBER_LIST",
4101 .synopsis = "Returns a list of interfaces on a queue",
4102 .syntax = "QUEUE_MEMBER_LIST(<queuename>)",
4103 .desc =
4104 "Returns a comma-separated list of members associated with the specified queue.\n",
4105 .read = queue_function_queuememberlist,
4108 static int reload_queues(void)
4110 struct call_queue *q;
4111 struct ast_config *cfg;
4112 char *cat, *tmp;
4113 struct ast_variable *var;
4114 struct member *cur, *newm;
4115 struct ao2_iterator mem_iter;
4116 int new;
4117 const char *general_val = NULL;
4118 char parse[80];
4119 char *interface;
4120 char *membername = NULL;
4121 int penalty;
4122 AST_DECLARE_APP_ARGS(args,
4123 AST_APP_ARG(interface);
4124 AST_APP_ARG(penalty);
4125 AST_APP_ARG(membername);
4128 if (!(cfg = ast_config_load("queues.conf"))) {
4129 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
4130 return 0;
4132 AST_LIST_LOCK(&queues);
4133 use_weight=0;
4134 /* Mark all non-realtime queues as dead for the moment */
4135 AST_LIST_TRAVERSE(&queues, q, list) {
4136 if (!q->realtime) {
4137 q->dead = 1;
4138 q->found = 0;
4142 /* Chug through config file */
4143 cat = NULL;
4144 while ((cat = ast_category_browse(cfg, cat)) ) {
4145 if (!strcasecmp(cat, "general")) {
4146 /* Initialize global settings */
4147 queue_persistent_members = 0;
4148 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
4149 queue_persistent_members = ast_true(general_val);
4150 autofill_default = 0;
4151 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill")))
4152 autofill_default = ast_true(general_val);
4153 montype_default = 0;
4154 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type")))
4155 if (!strcasecmp(general_val, "mixmonitor"))
4156 montype_default = 1;
4157 } else { /* Define queue */
4158 /* Look for an existing one */
4159 AST_LIST_TRAVERSE(&queues, q, list) {
4160 if (!strcmp(q->name, cat))
4161 break;
4163 if (!q) {
4164 /* Make one then */
4165 if (!(q = alloc_queue(cat))) {
4166 /* TODO: Handle memory allocation failure */
4168 new = 1;
4169 } else
4170 new = 0;
4171 if (q) {
4172 if (!new)
4173 ast_mutex_lock(&q->lock);
4174 /* Check if a queue with this name already exists */
4175 if (q->found) {
4176 ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", cat);
4177 if (!new)
4178 ast_mutex_unlock(&q->lock);
4179 continue;
4181 /* Re-initialize the queue, and clear statistics */
4182 init_queue(q);
4183 clear_queue(q);
4184 mem_iter = ao2_iterator_init(q->members, 0);
4185 while ((cur = ao2_iterator_next(&mem_iter))) {
4186 if (!cur->dynamic) {
4187 cur->delme = 1;
4189 ao2_ref(cur, -1);
4191 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
4192 if (!strcasecmp(var->name, "member")) {
4193 struct member tmpmem;
4194 membername = NULL;
4196 /* Add a new member */
4197 ast_copy_string(parse, var->value, sizeof(parse));
4199 AST_NONSTANDARD_APP_ARGS(args, parse, ',');
4201 interface = args.interface;
4202 if (!ast_strlen_zero(args.penalty)) {
4203 tmp = args.penalty;
4204 while (*tmp && *tmp < 33) tmp++;
4205 penalty = atoi(tmp);
4206 if (penalty < 0) {
4207 penalty = 0;
4209 } else
4210 penalty = 0;
4212 if (!ast_strlen_zero(args.membername)) {
4213 membername = args.membername;
4214 while (*membername && *membername < 33) membername++;
4217 /* Find the old position in the list */
4218 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
4219 cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK);
4221 newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0);
4222 ao2_link(q->members, newm);
4223 ao2_ref(newm, -1);
4224 newm = NULL;
4226 if (cur)
4227 ao2_ref(cur, -1);
4228 else {
4229 /* Add them to the master int list if necessary */
4230 add_to_interfaces(interface);
4231 q->membercount++;
4233 } else {
4234 queue_set_param(q, var->name, var->value, var->lineno, 1);
4238 /* Free remaining members marked as delme */
4239 mem_iter = ao2_iterator_init(q->members, 0);
4240 while ((cur = ao2_iterator_next(&mem_iter))) {
4241 if (! cur->delme) {
4242 ao2_ref(cur, -1);
4243 continue;
4246 q->membercount--;
4247 ao2_unlink(q->members, cur);
4248 remove_from_interfaces(cur->interface);
4249 ao2_ref(cur, -1);
4252 if (q->strategy == QUEUE_STRATEGY_ROUNDROBIN)
4253 rr_dep_warning();
4255 if (new) {
4256 AST_LIST_INSERT_HEAD(&queues, q, list);
4257 } else
4258 ast_mutex_unlock(&q->lock);
4262 ast_config_destroy(cfg);
4263 AST_LIST_TRAVERSE_SAFE_BEGIN(&queues, q, list) {
4264 if (q->dead) {
4265 AST_LIST_REMOVE_CURRENT(&queues, list);
4266 if (!q->count)
4267 destroy_queue(q);
4268 else
4269 ast_log(LOG_DEBUG, "XXX Leaking a little memory :( XXX\n");
4270 } else {
4271 ast_mutex_lock(&q->lock);
4272 mem_iter = ao2_iterator_init(q->members, 0);
4273 while ((cur = ao2_iterator_next(&mem_iter))) {
4274 if (cur->dynamic)
4275 q->membercount++;
4276 cur->status = ast_device_state(cur->interface);
4277 ao2_ref(cur, -1);
4279 ast_mutex_unlock(&q->lock);
4282 AST_LIST_TRAVERSE_SAFE_END;
4283 AST_LIST_UNLOCK(&queues);
4284 return 1;
4287 static int __queues_show(struct mansession *s, int manager, int fd, int argc, char **argv)
4289 struct call_queue *q;
4290 struct queue_ent *qe;
4291 struct member *mem;
4292 int pos, queue_show;
4293 time_t now;
4294 char max_buf[80];
4295 char *max;
4296 size_t max_left;
4297 float sl = 0;
4298 char *term = manager ? "\r\n" : "\n";
4299 struct ao2_iterator mem_iter;
4301 time(&now);
4302 if (argc == 2)
4303 queue_show = 0;
4304 else if (argc == 3)
4305 queue_show = 1;
4306 else
4307 return RESULT_SHOWUSAGE;
4309 /* We only want to load realtime queues when a specific queue is asked for. */
4310 if (queue_show)
4311 load_realtime_queue(argv[2]);
4313 AST_LIST_LOCK(&queues);
4314 if (AST_LIST_EMPTY(&queues)) {
4315 AST_LIST_UNLOCK(&queues);
4316 if (queue_show) {
4317 if (s)
4318 astman_append(s, "No such queue: %s.%s",argv[2], term);
4319 else
4320 ast_cli(fd, "No such queue: %s.%s",argv[2], term);
4321 } else {
4322 if (s)
4323 astman_append(s, "No queues.%s", term);
4324 else
4325 ast_cli(fd, "No queues.%s", term);
4327 return RESULT_SUCCESS;
4329 AST_LIST_TRAVERSE(&queues, q, list) {
4330 ast_mutex_lock(&q->lock);
4331 if (queue_show) {
4332 if (strcasecmp(q->name, argv[2]) != 0) {
4333 ast_mutex_unlock(&q->lock);
4334 if (!AST_LIST_NEXT(q, list)) {
4335 ast_cli(fd, "No such queue: %s.%s",argv[2], term);
4336 break;
4338 continue;
4341 max_buf[0] = '\0';
4342 max = max_buf;
4343 max_left = sizeof(max_buf);
4344 if (q->maxlen)
4345 ast_build_string(&max, &max_left, "%d", q->maxlen);
4346 else
4347 ast_build_string(&max, &max_left, "unlimited");
4348 sl = 0;
4349 if (q->callscompleted > 0)
4350 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
4351 if (s)
4352 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",
4353 q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->weight,
4354 q->callscompleted, q->callsabandoned,sl,q->servicelevel, term);
4355 else
4356 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",
4357 q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->weight, q->callscompleted, q->callsabandoned,sl,q->servicelevel, term);
4358 if (ao2_container_count(q->members)) {
4359 if (s)
4360 astman_append(s, " Members: %s", term);
4361 else
4362 ast_cli(fd, " Members: %s", term);
4363 mem_iter = ao2_iterator_init(q->members, 0);
4364 while ((mem = ao2_iterator_next(&mem_iter))) {
4365 max_buf[0] = '\0';
4366 max = max_buf;
4367 max_left = sizeof(max_buf);
4368 if (mem->penalty)
4369 ast_build_string(&max, &max_left, " with penalty %d", mem->penalty);
4370 if (mem->dynamic)
4371 ast_build_string(&max, &max_left, " (dynamic)");
4372 if (mem->realtime)
4373 ast_build_string(&max, &max_left, " (realtime)");
4374 if (mem->paused)
4375 ast_build_string(&max, &max_left, " (paused)");
4376 ast_build_string(&max, &max_left, " (%s)", devstate2str(mem->status));
4377 if (mem->calls) {
4378 ast_build_string(&max, &max_left, " has taken %d calls (last was %ld secs ago)",
4379 mem->calls, (long) (time(NULL) - mem->lastcall));
4380 } else
4381 ast_build_string(&max, &max_left, " has taken no calls yet");
4382 if (s)
4383 astman_append(s, " %s%s%s", mem->membername, max_buf, term);
4384 else
4385 ast_cli(fd, " %s%s%s", mem->membername, max_buf, term);
4386 ao2_ref(mem, -1);
4388 } else if (s)
4389 astman_append(s, " No Members%s", term);
4390 else
4391 ast_cli(fd, " No Members%s", term);
4392 if (q->head) {
4393 pos = 1;
4394 if (s)
4395 astman_append(s, " Callers: %s", term);
4396 else
4397 ast_cli(fd, " Callers: %s", term);
4398 for (qe = q->head; qe; qe = qe->next) {
4399 if (s)
4400 astman_append(s, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s",
4401 pos++, qe->chan->name, (long) (now - qe->start) / 60,
4402 (long) (now - qe->start) % 60, qe->prio, term);
4403 else
4404 ast_cli(fd, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s", pos++,
4405 qe->chan->name, (long) (now - qe->start) / 60,
4406 (long) (now - qe->start) % 60, qe->prio, term);
4408 } else if (s)
4409 astman_append(s, " No Callers%s", term);
4410 else
4411 ast_cli(fd, " No Callers%s", term);
4412 if (s)
4413 astman_append(s, "%s", term);
4414 else
4415 ast_cli(fd, "%s", term);
4416 ast_mutex_unlock(&q->lock);
4417 if (queue_show)
4418 break;
4420 AST_LIST_UNLOCK(&queues);
4421 return RESULT_SUCCESS;
4424 static int queue_show(int fd, int argc, char **argv)
4426 return __queues_show(NULL, 0, fd, argc, argv);
4429 static char *complete_queue(const char *line, const char *word, int pos, int state)
4431 struct call_queue *q;
4432 char *ret = NULL;
4433 int which = 0;
4434 int wordlen = strlen(word);
4436 AST_LIST_LOCK(&queues);
4437 AST_LIST_TRAVERSE(&queues, q, list) {
4438 if (!strncasecmp(word, q->name, wordlen) && ++which > state) {
4439 ret = ast_strdup(q->name);
4440 break;
4443 AST_LIST_UNLOCK(&queues);
4445 return ret;
4448 static char *complete_queue_show(const char *line, const char *word, int pos, int state)
4450 if (pos == 2)
4451 return complete_queue(line, word, pos, state);
4452 return NULL;
4455 /*!\brief callback to display queues status in manager
4456 \addtogroup Group_AMI
4458 static int manager_queues_show(struct mansession *s, const struct message *m)
4460 char *a[] = { "queue", "show" };
4462 __queues_show(s, 1, -1, 2, a);
4463 astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */
4465 return RESULT_SUCCESS;
4468 /* Dump queue status */
4469 static int manager_queues_status(struct mansession *s, const struct message *m)
4471 time_t now;
4472 int pos;
4473 const char *id = astman_get_header(m,"ActionID");
4474 const char *queuefilter = astman_get_header(m,"Queue");
4475 const char *memberfilter = astman_get_header(m,"Member");
4476 char idText[256] = "";
4477 struct call_queue *q;
4478 struct queue_ent *qe;
4479 float sl = 0;
4480 struct member *mem;
4481 struct ao2_iterator mem_iter;
4483 astman_send_ack(s, m, "Queue status will follow");
4484 time(&now);
4485 AST_LIST_LOCK(&queues);
4486 if (!ast_strlen_zero(id))
4487 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
4489 AST_LIST_TRAVERSE(&queues, q, list) {
4490 ast_mutex_lock(&q->lock);
4492 /* List queue properties */
4493 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
4494 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0);
4495 astman_append(s, "Event: QueueParams\r\n"
4496 "Queue: %s\r\n"
4497 "Max: %d\r\n"
4498 "Calls: %d\r\n"
4499 "Holdtime: %d\r\n"
4500 "Completed: %d\r\n"
4501 "Abandoned: %d\r\n"
4502 "ServiceLevel: %d\r\n"
4503 "ServicelevelPerf: %2.1f\r\n"
4504 "Weight: %d\r\n"
4505 "%s"
4506 "\r\n",
4507 q->name, q->maxlen, q->count, q->holdtime, q->callscompleted,
4508 q->callsabandoned, q->servicelevel, sl, q->weight, idText);
4509 /* List Queue Members */
4510 mem_iter = ao2_iterator_init(q->members, 0);
4511 while ((mem = ao2_iterator_next(&mem_iter))) {
4512 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter)) {
4513 astman_append(s, "Event: QueueMember\r\n"
4514 "Queue: %s\r\n"
4515 "Name: %s\r\n"
4516 "Location: %s\r\n"
4517 "Membership: %s\r\n"
4518 "Penalty: %d\r\n"
4519 "CallsTaken: %d\r\n"
4520 "LastCall: %d\r\n"
4521 "Status: %d\r\n"
4522 "Paused: %d\r\n"
4523 "%s"
4524 "\r\n",
4525 q->name, mem->membername, mem->interface, mem->dynamic ? "dynamic" : "static",
4526 mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText);
4528 ao2_ref(mem, -1);
4530 /* List Queue Entries */
4531 pos = 1;
4532 for (qe = q->head; qe; qe = qe->next) {
4533 astman_append(s, "Event: QueueEntry\r\n"
4534 "Queue: %s\r\n"
4535 "Position: %d\r\n"
4536 "Channel: %s\r\n"
4537 "CallerID: %s\r\n"
4538 "CallerIDName: %s\r\n"
4539 "Wait: %ld\r\n"
4540 "%s"
4541 "\r\n",
4542 q->name, pos++, qe->chan->name,
4543 S_OR(qe->chan->cid.cid_num, "unknown"),
4544 S_OR(qe->chan->cid.cid_name, "unknown"),
4545 (long) (now - qe->start), idText);
4548 ast_mutex_unlock(&q->lock);
4551 astman_append(s,
4552 "Event: QueueStatusComplete\r\n"
4553 "%s"
4554 "\r\n",idText);
4556 AST_LIST_UNLOCK(&queues);
4559 return RESULT_SUCCESS;
4562 static int manager_add_queue_member(struct mansession *s, const struct message *m)
4564 const char *queuename, *interface, *penalty_s, *paused_s, *membername;
4565 int paused, penalty = 0;
4567 queuename = astman_get_header(m, "Queue");
4568 interface = astman_get_header(m, "Interface");
4569 penalty_s = astman_get_header(m, "Penalty");
4570 paused_s = astman_get_header(m, "Paused");
4571 membername = astman_get_header(m, "MemberName");
4573 if (ast_strlen_zero(queuename)) {
4574 astman_send_error(s, m, "'Queue' not specified.");
4575 return 0;
4578 if (ast_strlen_zero(interface)) {
4579 astman_send_error(s, m, "'Interface' not specified.");
4580 return 0;
4583 if (ast_strlen_zero(penalty_s))
4584 penalty = 0;
4585 else if (sscanf(penalty_s, "%d", &penalty) != 1 || penalty < 0)
4586 penalty = 0;
4588 if (ast_strlen_zero(paused_s))
4589 paused = 0;
4590 else
4591 paused = abs(ast_true(paused_s));
4593 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members)) {
4594 case RES_OKAY:
4595 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", "");
4596 astman_send_ack(s, m, "Added interface to queue");
4597 break;
4598 case RES_EXISTS:
4599 astman_send_error(s, m, "Unable to add interface: Already there");
4600 break;
4601 case RES_NOSUCHQUEUE:
4602 astman_send_error(s, m, "Unable to add interface to queue: No such queue");
4603 break;
4604 case RES_OUTOFMEMORY:
4605 astman_send_error(s, m, "Out of memory");
4606 break;
4609 return 0;
4612 static int manager_remove_queue_member(struct mansession *s, const struct message *m)
4614 const char *queuename, *interface;
4616 queuename = astman_get_header(m, "Queue");
4617 interface = astman_get_header(m, "Interface");
4619 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
4620 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
4621 return 0;
4624 switch (remove_from_queue(queuename, interface)) {
4625 case RES_OKAY:
4626 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
4627 astman_send_ack(s, m, "Removed interface from queue");
4628 break;
4629 case RES_EXISTS:
4630 astman_send_error(s, m, "Unable to remove interface: Not there");
4631 break;
4632 case RES_NOSUCHQUEUE:
4633 astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
4634 break;
4635 case RES_OUTOFMEMORY:
4636 astman_send_error(s, m, "Out of memory");
4637 break;
4638 case RES_NOT_DYNAMIC:
4639 astman_send_error(s, m, "Member not dynamic");
4640 break;
4643 return 0;
4646 static int manager_pause_queue_member(struct mansession *s, const struct message *m)
4648 const char *queuename, *interface, *paused_s;
4649 int paused;
4651 interface = astman_get_header(m, "Interface");
4652 paused_s = astman_get_header(m, "Paused");
4653 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */
4655 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
4656 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
4657 return 0;
4660 paused = abs(ast_true(paused_s));
4662 if (set_member_paused(queuename, interface, paused))
4663 astman_send_error(s, m, "Interface not found");
4664 else
4665 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
4666 return 0;
4669 static int handle_queue_add_member(int fd, int argc, char *argv[])
4671 char *queuename, *interface, *membername = NULL;
4672 int penalty;
4674 if ((argc != 6) && (argc != 8) && (argc != 10)) {
4675 return RESULT_SHOWUSAGE;
4676 } else if (strcmp(argv[4], "to")) {
4677 return RESULT_SHOWUSAGE;
4678 } else if ((argc == 8) && strcmp(argv[6], "penalty")) {
4679 return RESULT_SHOWUSAGE;
4680 } else if ((argc == 10) && strcmp(argv[8], "as")) {
4681 return RESULT_SHOWUSAGE;
4684 queuename = argv[5];
4685 interface = argv[3];
4686 if (argc >= 8) {
4687 if (sscanf(argv[7], "%d", &penalty) == 1) {
4688 if (penalty < 0) {
4689 ast_cli(fd, "Penalty must be >= 0\n");
4690 penalty = 0;
4692 } else {
4693 ast_cli(fd, "Penalty must be an integer >= 0\n");
4694 penalty = 0;
4696 } else {
4697 penalty = 0;
4700 if (argc >= 10) {
4701 membername = argv[9];
4704 switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members)) {
4705 case RES_OKAY:
4706 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
4707 ast_cli(fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
4708 return RESULT_SUCCESS;
4709 case RES_EXISTS:
4710 ast_cli(fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
4711 return RESULT_FAILURE;
4712 case RES_NOSUCHQUEUE:
4713 ast_cli(fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
4714 return RESULT_FAILURE;
4715 case RES_OUTOFMEMORY:
4716 ast_cli(fd, "Out of memory\n");
4717 return RESULT_FAILURE;
4718 default:
4719 return RESULT_FAILURE;
4723 static char *complete_queue_add_member(const char *line, const char *word, int pos, int state)
4725 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
4726 switch (pos) {
4727 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
4728 return NULL;
4729 case 4: /* only one possible match, "to" */
4730 return state == 0 ? ast_strdup("to") : NULL;
4731 case 5: /* <queue> */
4732 return complete_queue(line, word, pos, state);
4733 case 6: /* only one possible match, "penalty" */
4734 return state == 0 ? ast_strdup("penalty") : NULL;
4735 case 7:
4736 if (state < 100) { /* 0-99 */
4737 char *num;
4738 if ((num = ast_malloc(3))) {
4739 sprintf(num, "%d", state);
4741 return num;
4742 } else {
4743 return NULL;
4745 case 8: /* only one possible match, "as" */
4746 return state == 0 ? ast_strdup("as") : NULL;
4747 case 9: /* Don't attempt to complete name of member (infinite possibilities) */
4748 return NULL;
4749 default:
4750 return NULL;
4754 static int handle_queue_remove_member(int fd, int argc, char *argv[])
4756 char *queuename, *interface;
4758 if (argc != 6) {
4759 return RESULT_SHOWUSAGE;
4760 } else if (strcmp(argv[4], "from")) {
4761 return RESULT_SHOWUSAGE;
4764 queuename = argv[5];
4765 interface = argv[3];
4767 switch (remove_from_queue(queuename, interface)) {
4768 case RES_OKAY:
4769 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
4770 ast_cli(fd, "Removed interface '%s' from queue '%s'\n", interface, queuename);
4771 return RESULT_SUCCESS;
4772 case RES_EXISTS:
4773 ast_cli(fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
4774 return RESULT_FAILURE;
4775 case RES_NOSUCHQUEUE:
4776 ast_cli(fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
4777 return RESULT_FAILURE;
4778 case RES_OUTOFMEMORY:
4779 ast_cli(fd, "Out of memory\n");
4780 return RESULT_FAILURE;
4781 case RES_NOT_DYNAMIC:
4782 ast_cli(fd, "Member not dynamic\n");
4783 return RESULT_FAILURE;
4784 default:
4785 return RESULT_FAILURE;
4789 static char *complete_queue_remove_member(const char *line, const char *word, int pos, int state)
4791 int which = 0;
4792 struct call_queue *q;
4793 struct member *m;
4794 struct ao2_iterator mem_iter;
4796 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
4797 if (pos > 5 || pos < 3)
4798 return NULL;
4799 if (pos == 4) /* only one possible match, 'from' */
4800 return state == 0 ? ast_strdup("from") : NULL;
4802 if (pos == 5) /* No need to duplicate code */
4803 return complete_queue(line, word, pos, state);
4805 /* here is the case for 3, <member> */
4806 if (!AST_LIST_EMPTY(&queues)) { /* XXX unnecessary ? the traverse does that for us */
4807 AST_LIST_TRAVERSE(&queues, q, list) {
4808 ast_mutex_lock(&q->lock);
4809 mem_iter = ao2_iterator_init(q->members, 0);
4810 while ((m = ao2_iterator_next(&mem_iter))) {
4811 if (++which > state) {
4812 char *tmp;
4813 ast_mutex_unlock(&q->lock);
4814 tmp = m->membername;
4815 ao2_ref(m, -1);
4816 return ast_strdup(tmp);
4818 ao2_ref(m, -1);
4820 ast_mutex_unlock(&q->lock);
4824 return NULL;
4827 static char queue_show_usage[] =
4828 "Usage: queue show\n"
4829 " Provides summary information on a specified queue.\n";
4831 static char qam_cmd_usage[] =
4832 "Usage: queue add member <channel> to <queue> [penalty <penalty>]\n";
4834 static char qrm_cmd_usage[] =
4835 "Usage: queue remove member <channel> from <queue>\n";
4837 static struct ast_cli_entry cli_show_queue_deprecated = {
4838 { "show", "queue", NULL },
4839 queue_show, NULL,
4840 NULL, complete_queue_show };
4842 static struct ast_cli_entry cli_add_queue_member_deprecated = {
4843 { "add", "queue", "member", NULL },
4844 handle_queue_add_member, NULL,
4845 NULL, complete_queue_add_member };
4847 static struct ast_cli_entry cli_remove_queue_member_deprecated = {
4848 { "remove", "queue", "member", NULL },
4849 handle_queue_remove_member, NULL,
4850 NULL, complete_queue_remove_member };
4852 static struct ast_cli_entry cli_queue[] = {
4853 /* Deprecated */
4854 { { "show", "queues", NULL },
4855 queue_show, NULL,
4856 NULL, NULL },
4858 { { "queue", "show", NULL },
4859 queue_show, "Show status of a specified queue",
4860 queue_show_usage, complete_queue_show, &cli_show_queue_deprecated },
4862 { { "queue", "add", "member", NULL },
4863 handle_queue_add_member, "Add a channel to a specified queue",
4864 qam_cmd_usage, complete_queue_add_member, &cli_add_queue_member_deprecated },
4866 { { "queue", "remove", "member", NULL },
4867 handle_queue_remove_member, "Removes a channel from a specified queue",
4868 qrm_cmd_usage, complete_queue_remove_member, &cli_remove_queue_member_deprecated },
4871 static int unload_module(void)
4873 int res;
4875 if (device_state.thread != AST_PTHREADT_NULL) {
4876 device_state.stop = 1;
4877 ast_mutex_lock(&device_state.lock);
4878 ast_cond_signal(&device_state.cond);
4879 ast_mutex_unlock(&device_state.lock);
4880 pthread_join(device_state.thread, NULL);
4883 ast_cli_unregister_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry));
4884 res = ast_manager_unregister("QueueStatus");
4885 res |= ast_manager_unregister("Queues");
4886 res |= ast_manager_unregister("QueueStatus");
4887 res |= ast_manager_unregister("QueueAdd");
4888 res |= ast_manager_unregister("QueueRemove");
4889 res |= ast_manager_unregister("QueuePause");
4890 res |= ast_unregister_application(app_aqm);
4891 res |= ast_unregister_application(app_rqm);
4892 res |= ast_unregister_application(app_pqm);
4893 res |= ast_unregister_application(app_upqm);
4894 res |= ast_unregister_application(app_ql);
4895 res |= ast_unregister_application(app);
4896 res |= ast_custom_function_unregister(&queueagentcount_function);
4897 res |= ast_custom_function_unregister(&queuemembercount_function);
4898 res |= ast_custom_function_unregister(&queuememberlist_function);
4899 res |= ast_custom_function_unregister(&queuewaitingcount_function);
4900 ast_devstate_del(statechange_queue, NULL);
4902 ast_module_user_hangup_all();
4904 clear_and_free_interfaces();
4906 return res;
4909 static int load_module(void)
4911 int res;
4913 if (!reload_queues())
4914 return AST_MODULE_LOAD_DECLINE;
4916 if (queue_persistent_members)
4917 reload_queue_members();
4919 ast_mutex_init(&device_state.lock);
4920 ast_cond_init(&device_state.cond, NULL);
4921 ast_pthread_create(&device_state.thread, NULL, device_state_thread, NULL);
4923 ast_cli_register_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry));
4924 res = ast_register_application(app, queue_exec, synopsis, descrip);
4925 res |= ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip);
4926 res |= ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip);
4927 res |= ast_register_application(app_pqm, pqm_exec, app_pqm_synopsis, app_pqm_descrip);
4928 res |= ast_register_application(app_upqm, upqm_exec, app_upqm_synopsis, app_upqm_descrip);
4929 res |= ast_register_application(app_ql, ql_exec, app_ql_synopsis, app_ql_descrip);
4930 res |= ast_manager_register("Queues", 0, manager_queues_show, "Queues");
4931 res |= ast_manager_register("QueueStatus", 0, manager_queues_status, "Queue Status");
4932 res |= ast_manager_register("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member, "Add interface to queue.");
4933 res |= ast_manager_register("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member, "Remove interface from queue.");
4934 res |= ast_manager_register("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member, "Makes a queue member temporarily unavailable");
4935 res |= ast_custom_function_register(&queueagentcount_function);
4936 res |= ast_custom_function_register(&queuemembercount_function);
4937 res |= ast_custom_function_register(&queuememberlist_function);
4938 res |= ast_custom_function_register(&queuewaitingcount_function);
4939 res |= ast_devstate_add(statechange_queue, NULL);
4941 return res;
4944 static int reload(void)
4946 reload_queues();
4947 return 0;
4950 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "True Call Queueing",
4951 .load = load_module,
4952 .unload = unload_module,
4953 .reload = reload,