Adds DAHDI support alongside Zaptel. DAHDI usage favored, but all Zap stuff should...
[asterisk-bristuff.git] / apps / app_queue.c
blob01fdcf3aa9b278253c5137246c8f5dbfc4055378
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 || stat == QUEUE_NO_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 - 3)
1765 j = len - 3;
1766 vars[j++] = '\r';
1767 vars[j++] = '\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;
1787 const char *macrocontext, *macroexten;
1789 /* on entry here, we know that tmp->chan == NULL */
1790 if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
1791 if (option_debug)
1792 ast_log(LOG_DEBUG, "Wrapuptime not yet expired for %s\n", tmp->interface);
1793 if (qe->chan->cdr)
1794 ast_cdr_busy(qe->chan->cdr);
1795 tmp->stillgoing = 0;
1796 (*busies)++;
1797 return 0;
1800 if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
1801 if (option_debug)
1802 ast_log(LOG_DEBUG, "%s in use, can't receive call\n", tmp->interface);
1803 if (qe->chan->cdr)
1804 ast_cdr_busy(qe->chan->cdr);
1805 tmp->stillgoing = 0;
1806 return 0;
1809 if (tmp->member->paused) {
1810 if (option_debug)
1811 ast_log(LOG_DEBUG, "%s paused, can't receive call\n", tmp->interface);
1812 if (qe->chan->cdr)
1813 ast_cdr_busy(qe->chan->cdr);
1814 tmp->stillgoing = 0;
1815 return 0;
1817 if (use_weight && compare_weight(qe->parent,tmp->member)) {
1818 ast_log(LOG_DEBUG, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
1819 if (qe->chan->cdr)
1820 ast_cdr_busy(qe->chan->cdr);
1821 tmp->stillgoing = 0;
1822 (*busies)++;
1823 return 0;
1826 ast_copy_string(tech, tmp->interface, sizeof(tech));
1827 if ((location = strchr(tech, '/')))
1828 *location++ = '\0';
1829 else
1830 location = "";
1832 /* Request the peer */
1833 tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
1834 if (!tmp->chan) { /* If we can't, just go on to the next call */
1835 if (qe->chan->cdr)
1836 ast_cdr_busy(qe->chan->cdr);
1837 tmp->stillgoing = 0;
1839 update_status(tmp->member->interface, ast_device_state(tmp->member->interface));
1841 ast_mutex_lock(&qe->parent->lock);
1842 qe->parent->rrpos++;
1843 ast_mutex_unlock(&qe->parent->lock);
1845 (*busies)++;
1846 return 0;
1849 tmp->chan->appl = "AppQueue";
1850 tmp->chan->data = "(Outgoing Line)";
1851 tmp->chan->whentohangup = 0;
1852 if (tmp->chan->cid.cid_num)
1853 free(tmp->chan->cid.cid_num);
1854 tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num);
1855 if (tmp->chan->cid.cid_name)
1856 free(tmp->chan->cid.cid_name);
1857 tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name);
1858 if (tmp->chan->cid.cid_ani)
1859 free(tmp->chan->cid.cid_ani);
1860 tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani);
1862 /* Inherit specially named variables from parent channel */
1863 ast_channel_inherit_variables(qe->chan, tmp->chan);
1865 /* Presense of ADSI CPE on outgoing channel follows ours */
1866 tmp->chan->adsicpe = qe->chan->adsicpe;
1868 /* Inherit context and extension */
1869 ast_channel_lock(qe->chan);
1870 macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT");
1871 if (!ast_strlen_zero(macrocontext))
1872 ast_copy_string(tmp->chan->dialcontext, macrocontext, sizeof(tmp->chan->dialcontext));
1873 else
1874 ast_copy_string(tmp->chan->dialcontext, qe->chan->context, sizeof(tmp->chan->dialcontext));
1875 macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN");
1876 if (!ast_strlen_zero(macroexten))
1877 ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten));
1878 else
1879 ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten));
1880 ast_channel_unlock(qe->chan);
1882 /* Place the call, but don't wait on the answer */
1883 if ((res = ast_call(tmp->chan, location, 0))) {
1884 /* Again, keep going even if there's an error */
1885 if (option_debug)
1886 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
1887 if (option_verbose > 2)
1888 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface);
1889 do_hang(tmp);
1890 (*busies)++;
1891 return 0;
1892 } else if (qe->parent->eventwhencalled) {
1893 char vars[2048];
1895 manager_event(EVENT_FLAG_AGENT, "AgentCalled",
1896 "AgentCalled: %s\r\n"
1897 "AgentName: %s\r\n"
1898 "ChannelCalling: %s\r\n"
1899 "CallerID: %s\r\n"
1900 "CallerIDName: %s\r\n"
1901 "Context: %s\r\n"
1902 "Extension: %s\r\n"
1903 "Priority: %d\r\n"
1904 "%s",
1905 tmp->interface, tmp->member->membername, qe->chan->name,
1906 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
1907 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
1908 qe->chan->context, qe->chan->exten, qe->chan->priority,
1909 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
1910 if (option_verbose > 2)
1911 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface);
1914 return 1;
1917 /*! \brief find the entry with the best metric, or NULL */
1918 static struct callattempt *find_best(struct callattempt *outgoing)
1920 struct callattempt *best = NULL, *cur;
1922 for (cur = outgoing; cur; cur = cur->q_next) {
1923 if (cur->stillgoing && /* Not already done */
1924 !cur->chan && /* Isn't already going */
1925 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */
1926 best = cur;
1930 return best;
1933 /*! \brief Place a call to a queue member
1935 * Once metrics have been calculated for each member, this function is used
1936 * to place a call to the appropriate member (or members). The low-level
1937 * channel-handling and error detection is handled in ring_entry
1939 * Returns 1 if a member was called successfully, 0 otherwise
1941 static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
1943 int ret = 0;
1945 while (ret == 0) {
1946 struct callattempt *best = find_best(outgoing);
1947 if (!best) {
1948 if (option_debug)
1949 ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n");
1950 break;
1952 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
1953 struct callattempt *cur;
1954 /* Ring everyone who shares this best metric (for ringall) */
1955 for (cur = outgoing; cur; cur = cur->q_next) {
1956 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
1957 if (option_debug)
1958 ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
1959 ret |= ring_entry(qe, cur, busies);
1962 } else {
1963 /* Ring just the best channel */
1964 if (option_debug)
1965 ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric);
1966 ret = ring_entry(qe, best, busies);
1970 return ret;
1973 static int store_next(struct queue_ent *qe, struct callattempt *outgoing)
1975 struct callattempt *best = find_best(outgoing);
1977 if (best) {
1978 /* Ring just the best channel */
1979 if (option_debug)
1980 ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric);
1981 qe->parent->rrpos = best->metric % 1000;
1982 } else {
1983 /* Just increment rrpos */
1984 if (qe->parent->wrapped) {
1985 /* No more channels, start over */
1986 qe->parent->rrpos = 0;
1987 } else {
1988 /* Prioritize next entry */
1989 qe->parent->rrpos++;
1992 qe->parent->wrapped = 0;
1994 return 0;
1997 static int say_periodic_announcement(struct queue_ent *qe)
1999 int res = 0;
2000 time_t now;
2002 /* Get the current time */
2003 time(&now);
2005 /* Check to see if it is time to announce */
2006 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
2007 return 0;
2009 /* Stop the music on hold so we can play our own file */
2010 ast_moh_stop(qe->chan);
2012 if (option_verbose > 2)
2013 ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n");
2015 /* Check to make sure we have a sound file. If not, reset to the first sound file */
2016 if (qe->last_periodic_announce_sound >= MAX_PERIODIC_ANNOUNCEMENTS || !strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound])) {
2017 qe->last_periodic_announce_sound = 0;
2020 /* play the announcement */
2021 res = play_file(qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]);
2023 if ((res > 0 && !valid_exit(qe, res)) || res < 0)
2024 res = 0;
2026 /* Resume Music on Hold if the caller is going to stay in the queue */
2027 if (!res)
2028 ast_moh_start(qe->chan, qe->moh, NULL);
2030 /* update last_periodic_announce_time */
2031 qe->last_periodic_announce_time = now;
2033 /* Update the current periodic announcement to the next announcement */
2034 qe->last_periodic_announce_sound++;
2036 return res;
2039 static void record_abandoned(struct queue_ent *qe)
2041 ast_mutex_lock(&qe->parent->lock);
2042 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
2043 "Queue: %s\r\n"
2044 "Uniqueid: %s\r\n"
2045 "Position: %d\r\n"
2046 "OriginalPosition: %d\r\n"
2047 "HoldTime: %d\r\n",
2048 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start));
2050 qe->parent->callsabandoned++;
2051 ast_mutex_unlock(&qe->parent->lock);
2054 /*! \brief RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. */
2055 static void rna(int rnatime, struct queue_ent *qe, char *interface, char *membername)
2057 if (option_verbose > 2)
2058 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", rnatime);
2059 ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
2060 if (qe->parent->autopause) {
2061 if (!set_member_paused(qe->parent->name, interface, 1)) {
2062 if (option_verbose > 2)
2063 ast_verbose( VERBOSE_PREFIX_3 "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name);
2064 } else {
2065 if (option_verbose > 2)
2066 ast_verbose( VERBOSE_PREFIX_3 "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
2069 return;
2072 #define AST_MAX_WATCHERS 256
2073 /*! \brief Wait for a member to answer the call
2075 * \param[in] qe the queue_ent corresponding to the caller in the queue
2076 * \param[in] outgoing the list of callattempts. Relevant ones will have their chan and stillgoing parameters non-zero
2077 * \param[in] to the amount of time (in milliseconds) to wait for a response
2078 * \param[out] digit if a user presses a digit to exit the queue, this is the digit the caller pressed
2079 * \param[in] prebusies number of busy members calculated prior to calling wait_for_answer
2080 * \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
2081 * \param[in] forwardsallowed used to detect if we should allow call forwarding, based on the 'i' option to Queue()
2083 static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
2085 char *queue = qe->parent->name;
2086 struct callattempt *o, *start = NULL, *prev = NULL;
2087 int status;
2088 int numbusies = prebusies;
2089 int numnochan = 0;
2090 int stillgoing = 0;
2091 int orig = *to;
2092 struct ast_frame *f;
2093 struct callattempt *peer = NULL;
2094 struct ast_channel *winner;
2095 struct ast_channel *in = qe->chan;
2096 char on[80] = "";
2097 char membername[80] = "";
2098 long starttime = 0;
2099 long endtime = 0;
2101 starttime = (long) time(NULL);
2103 while (*to && !peer) {
2104 int numlines, retry, pos = 1;
2105 struct ast_channel *watchers[AST_MAX_WATCHERS];
2106 watchers[0] = in;
2107 start = NULL;
2109 for (retry = 0; retry < 2; retry++) {
2110 numlines = 0;
2111 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
2112 if (o->stillgoing) { /* Keep track of important channels */
2113 stillgoing = 1;
2114 if (o->chan) {
2115 watchers[pos++] = o->chan;
2116 if (!start)
2117 start = o;
2118 else
2119 prev->call_next = o;
2120 prev = o;
2123 numlines++;
2125 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
2126 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */)
2127 break;
2128 /* On "ringall" strategy we only move to the next penalty level
2129 when *all* ringing phones are done in the current penalty level */
2130 ring_one(qe, outgoing, &numbusies);
2131 /* and retry... */
2133 if (pos == 1 /* not found */) {
2134 if (numlines == (numbusies + numnochan)) {
2135 ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
2136 } else {
2137 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan);
2139 *to = 0;
2140 return NULL;
2142 winner = ast_waitfor_n(watchers, pos, to);
2143 for (o = start; o; o = o->call_next) {
2144 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
2145 if (!peer) {
2146 if (option_verbose > 2)
2147 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
2148 peer = o;
2150 } else if (o->chan && (o->chan == winner)) {
2152 ast_copy_string(on, o->member->interface, sizeof(on));
2153 ast_copy_string(membername, o->member->membername, sizeof(membername));
2155 if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) {
2156 if (option_verbose > 2)
2157 ast_verbose(VERBOSE_PREFIX_3 "Forwarding %s to '%s' prevented.\n", in->name, o->chan->call_forward);
2158 numnochan++;
2159 do_hang(o);
2160 winner = NULL;
2161 continue;
2162 } else if (!ast_strlen_zero(o->chan->call_forward)) {
2163 char tmpchan[256];
2164 char *stuff;
2165 char *tech;
2167 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
2168 if ((stuff = strchr(tmpchan, '/'))) {
2169 *stuff++ = '\0';
2170 tech = tmpchan;
2171 } else {
2172 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
2173 stuff = tmpchan;
2174 tech = "Local";
2176 /* Before processing channel, go ahead and check for forwarding */
2177 if (option_verbose > 2)
2178 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
2179 /* Setup parameters */
2180 o->chan = ast_request(tech, in->nativeformats, stuff, &status);
2181 if (!o->chan) {
2182 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
2183 o->stillgoing = 0;
2184 numnochan++;
2185 } else {
2186 ast_channel_inherit_variables(in, o->chan);
2187 ast_channel_datastore_inherit(in, o->chan);
2188 if (o->chan->cid.cid_num)
2189 free(o->chan->cid.cid_num);
2190 o->chan->cid.cid_num = ast_strdup(in->cid.cid_num);
2192 if (o->chan->cid.cid_name)
2193 free(o->chan->cid.cid_name);
2194 o->chan->cid.cid_name = ast_strdup(in->cid.cid_name);
2196 ast_string_field_set(o->chan, accountcode, in->accountcode);
2197 o->chan->cdrflags = in->cdrflags;
2199 if (in->cid.cid_ani) {
2200 if (o->chan->cid.cid_ani)
2201 free(o->chan->cid.cid_ani);
2202 o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani);
2204 if (o->chan->cid.cid_rdnis)
2205 free(o->chan->cid.cid_rdnis);
2206 o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten));
2207 if (ast_call(o->chan, tmpchan, 0)) {
2208 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
2209 do_hang(o);
2210 numnochan++;
2213 /* Hangup the original channel now, in case we needed it */
2214 ast_hangup(winner);
2215 continue;
2217 f = ast_read(winner);
2218 if (f) {
2219 if (f->frametype == AST_FRAME_CONTROL) {
2220 switch (f->subclass) {
2221 case AST_CONTROL_ANSWER:
2222 /* This is our guy if someone answered. */
2223 if (!peer) {
2224 if (option_verbose > 2)
2225 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
2226 peer = o;
2228 break;
2229 case AST_CONTROL_BUSY:
2230 if (option_verbose > 2)
2231 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
2232 if (in->cdr)
2233 ast_cdr_busy(in->cdr);
2234 do_hang(o);
2235 endtime = (long)time(NULL);
2236 endtime -= starttime;
2237 rna(endtime*1000, qe, on, membername);
2238 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2239 if (qe->parent->timeoutrestart)
2240 *to = orig;
2241 ring_one(qe, outgoing, &numbusies);
2243 numbusies++;
2244 break;
2245 case AST_CONTROL_CONGESTION:
2246 if (option_verbose > 2)
2247 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
2248 if (in->cdr)
2249 ast_cdr_busy(in->cdr);
2250 endtime = (long)time(NULL);
2251 endtime -= starttime;
2252 rna(endtime*1000, qe, on, membername);
2253 do_hang(o);
2254 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2255 if (qe->parent->timeoutrestart)
2256 *to = orig;
2257 ring_one(qe, outgoing, &numbusies);
2259 numbusies++;
2260 break;
2261 case AST_CONTROL_RINGING:
2262 if (option_verbose > 2)
2263 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
2264 break;
2265 case AST_CONTROL_OFFHOOK:
2266 /* Ignore going off hook */
2267 break;
2268 default:
2269 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
2272 ast_frfree(f);
2273 } else {
2274 endtime = (long) time(NULL) - starttime;
2275 rna(endtime * 1000, qe, on, membername);
2276 do_hang(o);
2277 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2278 if (qe->parent->timeoutrestart)
2279 *to = orig;
2280 ring_one(qe, outgoing, &numbusies);
2285 if (winner == in) {
2286 f = ast_read(in);
2287 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
2288 /* Got hung up */
2289 *to = -1;
2290 if (f)
2291 ast_frfree(f);
2292 return NULL;
2294 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) {
2295 if (option_verbose > 3)
2296 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
2297 *to = 0;
2298 ast_frfree(f);
2299 return NULL;
2301 if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass)) {
2302 if (option_verbose > 3)
2303 ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass);
2304 *to = 0;
2305 *digit = f->subclass;
2306 ast_frfree(f);
2307 return NULL;
2309 ast_frfree(f);
2311 if (!*to) {
2312 for (o = start; o; o = o->call_next)
2313 rna(orig, qe, o->interface, o->member->membername);
2317 return peer;
2319 /*! \brief Check if we should start attempting to call queue members
2321 * The behavior of this function is dependent first on whether autofill is enabled
2322 * and second on whether the ring strategy is ringall. If autofill is not enabled,
2323 * then return true if we're the head of the queue. If autofill is enabled, then
2324 * we count the available members and see if the number of available members is enough
2325 * that given our position in the queue, we would theoretically be able to connect to
2326 * one of those available members
2328 static int is_our_turn(struct queue_ent *qe)
2330 struct queue_ent *ch;
2331 struct member *cur;
2332 int avl = 0;
2333 int idx = 0;
2334 int res;
2336 if (!qe->parent->autofill) {
2337 /* Atomically read the parent head -- does not need a lock */
2338 ch = qe->parent->head;
2339 /* If we are now at the top of the head, break out */
2340 if (ch == qe) {
2341 if (option_debug)
2342 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
2343 res = 1;
2344 } else {
2345 if (option_debug)
2346 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
2347 res = 0;
2350 } else {
2351 /* This needs a lock. How many members are available to be served? */
2352 ast_mutex_lock(&qe->parent->lock);
2354 ch = qe->parent->head;
2356 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
2357 if (option_debug)
2358 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");
2359 avl = 1;
2360 } else {
2361 struct ao2_iterator mem_iter = ao2_iterator_init(qe->parent->members, 0);
2362 while ((cur = ao2_iterator_next(&mem_iter))) {
2363 switch (cur->status) {
2364 case AST_DEVICE_INUSE:
2365 if (!qe->parent->ringinuse)
2366 break;
2367 /* else fall through */
2368 case AST_DEVICE_NOT_INUSE:
2369 case AST_DEVICE_UNKNOWN:
2370 if (!cur->paused)
2371 avl++;
2372 break;
2374 ao2_ref(cur, -1);
2378 if (option_debug)
2379 ast_log(LOG_DEBUG, "There are %d available members.\n", avl);
2381 while ((idx < avl) && (ch) && (ch != qe)) {
2382 if (!ch->pending)
2383 idx++;
2384 ch = ch->next;
2387 /* If the queue entry is within avl [the number of available members] calls from the top ... */
2388 if (ch && idx < avl) {
2389 if (option_debug)
2390 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
2391 res = 1;
2392 } else {
2393 if (option_debug)
2394 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
2395 res = 0;
2398 ast_mutex_unlock(&qe->parent->lock);
2401 return res;
2403 /*! \brief The waiting areas for callers who are not actively calling members
2405 * This function is one large loop. This function will return if a caller
2406 * either exits the queue or it becomes that caller's turn to attempt calling
2407 * queue members. Inside the loop, we service the caller with periodic announcements,
2408 * holdtime announcements, etc. as configured in queues.conf
2410 * \retval 0 if the caller's turn has arrived
2411 * \retval -1 if the caller should exit the queue.
2413 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
2415 int res = 0;
2417 /* This is the holding pen for callers 2 through maxlen */
2418 for (;;) {
2419 enum queue_member_status stat;
2421 if (is_our_turn(qe))
2422 break;
2424 /* If we have timed out, break out */
2425 if (qe->expire && (time(NULL) > qe->expire)) {
2426 *reason = QUEUE_TIMEOUT;
2427 break;
2430 stat = get_member_status(qe->parent, qe->max_penalty);
2432 /* leave the queue if no agents, if enabled */
2433 if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
2434 *reason = QUEUE_LEAVEEMPTY;
2435 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
2436 leave_queue(qe);
2437 break;
2440 /* leave the queue if no reachable agents, if enabled */
2441 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
2442 *reason = QUEUE_LEAVEUNAVAIL;
2443 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
2444 leave_queue(qe);
2445 break;
2448 /* Make a position announcement, if enabled */
2449 if (qe->parent->announcefrequency && !ringing &&
2450 (res = say_position(qe)))
2451 break;
2453 /* Make a periodic announcement, if enabled */
2454 if (qe->parent->periodicannouncefrequency && !ringing &&
2455 (res = say_periodic_announcement(qe)))
2456 break;
2458 /* Wait a second before checking again */
2459 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
2460 if (res > 0 && !valid_exit(qe, res))
2461 res = 0;
2462 else
2463 break;
2467 return res;
2470 static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl)
2472 ast_mutex_lock(&q->lock);
2473 time(&member->lastcall);
2474 member->calls++;
2475 q->callscompleted++;
2476 if (callcompletedinsl)
2477 q->callscompletedinsl++;
2478 ast_mutex_unlock(&q->lock);
2479 return 0;
2482 /*! \brief Calculate the metric of each member in the outgoing callattempts
2484 * A numeric metric is given to each member depending on the ring strategy used
2485 * by the queue. Members with lower metrics will be called before members with
2486 * higher metrics
2488 static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
2490 if (qe->max_penalty && (mem->penalty > qe->max_penalty))
2491 return -1;
2493 switch (q->strategy) {
2494 case QUEUE_STRATEGY_RINGALL:
2495 /* Everyone equal, except for penalty */
2496 tmp->metric = mem->penalty * 1000000;
2497 break;
2498 case QUEUE_STRATEGY_ROUNDROBIN:
2499 if (!pos) {
2500 if (!q->wrapped) {
2501 /* No more channels, start over */
2502 q->rrpos = 0;
2503 } else {
2504 /* Prioritize next entry */
2505 q->rrpos++;
2507 q->wrapped = 0;
2509 /* Fall through */
2510 case QUEUE_STRATEGY_RRMEMORY:
2511 if (pos < q->rrpos) {
2512 tmp->metric = 1000 + pos;
2513 } else {
2514 if (pos > q->rrpos)
2515 /* Indicate there is another priority */
2516 q->wrapped = 1;
2517 tmp->metric = pos;
2519 tmp->metric += mem->penalty * 1000000;
2520 break;
2521 case QUEUE_STRATEGY_RANDOM:
2522 tmp->metric = ast_random() % 1000;
2523 tmp->metric += mem->penalty * 1000000;
2524 break;
2525 case QUEUE_STRATEGY_FEWESTCALLS:
2526 tmp->metric = mem->calls;
2527 tmp->metric += mem->penalty * 1000000;
2528 break;
2529 case QUEUE_STRATEGY_LEASTRECENT:
2530 if (!mem->lastcall)
2531 tmp->metric = 0;
2532 else
2533 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
2534 tmp->metric += mem->penalty * 1000000;
2535 break;
2536 default:
2537 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
2538 break;
2540 return 0;
2542 /*! \brief A large function which calls members, updates statistics, and bridges the caller and a member
2544 * Here is the process of this function
2545 * 1. Process any options passed to the Queue() application. Options here mean the third argument to Queue()
2546 * 2. Iterate trough the members of the queue, creating a callattempt corresponding to each member. During this
2547 * iteration, we also check the dialed_interfaces datastore to see if we have already attempted calling this
2548 * member. If we have, we do not create a callattempt. This is in place to prevent call forwarding loops. Also
2549 * during each iteration, we call calc_metric to determine which members should be rung when.
2550 * 3. Call ring_one to place a call to the appropriate member(s)
2551 * 4. Call wait_for_answer to wait for an answer. If no one answers, return.
2552 * 5. Take care of any holdtime announcements, member delays, or other options which occur after a call has been answered.
2553 * 6. Start the monitor or mixmonitor if the option is set
2554 * 7. Remove the caller from the queue to allow other callers to advance
2555 * 8. Bridge the call.
2556 * 9. Do any post processing after the call has disconnected.
2558 * \param[in] qe the queue_ent structure which corresponds to the caller attempting to reach members
2559 * \param[in] options the options passed as the third parameter to the Queue() application
2560 * \param[in] url the url passed as the fourth parameter to the Queue() application
2561 * \param[in,out] tries the number of times we have tried calling queue members
2562 * \param[out] noption set if the call to Queue() has the 'n' option set.
2563 * \param[in] agi the agi passed as the fifth parameter to the Queue() application
2566 static int try_calling(struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *tries, int *noption, const char *agi)
2568 struct member *cur;
2569 struct callattempt *outgoing = NULL; /* the list of calls we are building */
2570 int to;
2571 char oldexten[AST_MAX_EXTENSION]="";
2572 char oldcontext[AST_MAX_CONTEXT]="";
2573 char queuename[256]="";
2574 struct ast_channel *peer;
2575 struct ast_channel *which;
2576 struct callattempt *lpeer;
2577 struct member *member;
2578 struct ast_app *app;
2579 int res = 0, bridge = 0;
2580 int numbusies = 0;
2581 int x=0;
2582 char *announce = NULL;
2583 char digit = 0;
2584 time_t callstart;
2585 time_t now = time(NULL);
2586 struct ast_bridge_config bridge_config;
2587 char nondataquality = 1;
2588 char *agiexec = NULL;
2589 int ret = 0;
2590 const char *monitorfilename;
2591 const char *monitor_exec;
2592 const char *monitor_options;
2593 char tmpid[256], tmpid2[256];
2594 char meid[1024], meid2[1024];
2595 char mixmonargs[1512];
2596 struct ast_app *mixmonapp = NULL;
2597 char *p;
2598 char vars[2048];
2599 int forwardsallowed = 1;
2600 int callcompletedinsl;
2601 struct ao2_iterator memi;
2602 struct ast_datastore *datastore;
2604 ast_channel_lock(qe->chan);
2605 datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL);
2606 ast_channel_unlock(qe->chan);
2608 memset(&bridge_config, 0, sizeof(bridge_config));
2609 time(&now);
2611 for (; options && *options; options++)
2612 switch (*options) {
2613 case 't':
2614 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
2615 break;
2616 case 'T':
2617 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
2618 break;
2619 case 'w':
2620 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
2621 break;
2622 case 'W':
2623 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
2624 break;
2625 case 'd':
2626 nondataquality = 0;
2627 break;
2628 case 'h':
2629 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
2630 break;
2631 case 'H':
2632 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
2633 break;
2634 case 'n':
2635 if (qe->parent->strategy == QUEUE_STRATEGY_ROUNDROBIN || qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY)
2636 (*tries)++;
2637 else
2638 *tries = qe->parent->membercount;
2639 *noption = 1;
2640 break;
2641 case 'i':
2642 forwardsallowed = 0;
2643 break;
2646 /* Hold the lock while we setup the outgoing calls */
2647 if (use_weight)
2648 AST_LIST_LOCK(&queues);
2649 ast_mutex_lock(&qe->parent->lock);
2650 if (option_debug)
2651 ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n",
2652 qe->chan->name);
2653 ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
2654 if (!ast_strlen_zero(qe->announce))
2655 announce = qe->announce;
2656 if (!ast_strlen_zero(announceoverride))
2657 announce = announceoverride;
2659 memi = ao2_iterator_init(qe->parent->members, 0);
2660 while ((cur = ao2_iterator_next(&memi))) {
2661 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
2662 struct ast_dialed_interface *di;
2663 AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces;
2664 if (!tmp) {
2665 ao2_ref(cur, -1);
2666 ast_mutex_unlock(&qe->parent->lock);
2667 if (use_weight)
2668 AST_LIST_UNLOCK(&queues);
2669 goto out;
2671 if (!datastore) {
2672 if (!(datastore = ast_channel_datastore_alloc(&dialed_interface_info, NULL))) {
2673 ao2_ref(cur, -1);
2674 ast_mutex_unlock(&qe->parent->lock);
2675 if (use_weight)
2676 AST_LIST_UNLOCK(&queues);
2677 free(tmp);
2678 goto out;
2680 datastore->inheritance = DATASTORE_INHERIT_FOREVER;
2681 if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) {
2682 ao2_ref(cur, -1);
2683 ast_mutex_unlock(&qe->parent->lock);
2684 if (use_weight)
2685 AST_LIST_UNLOCK(&queues);
2686 free(tmp);
2687 goto out;
2689 datastore->data = dialed_interfaces;
2690 AST_LIST_HEAD_INIT(dialed_interfaces);
2692 ast_channel_lock(qe->chan);
2693 ast_channel_datastore_add(qe->chan, datastore);
2694 ast_channel_unlock(qe->chan);
2695 } else
2696 dialed_interfaces = datastore->data;
2698 AST_LIST_LOCK(dialed_interfaces);
2699 AST_LIST_TRAVERSE(dialed_interfaces, di, list) {
2700 if (!strcasecmp(cur->interface, di->interface)) {
2701 ast_log(LOG_DEBUG, "Skipping dialing interface '%s' since it has already been dialed\n",
2702 di->interface);
2703 break;
2706 AST_LIST_UNLOCK(dialed_interfaces);
2708 if (di) {
2709 free(tmp);
2710 continue;
2713 /* It is always ok to dial a Local interface. We only keep track of
2714 * which "real" interfaces have been dialed. The Local channel will
2715 * inherit this list so that if it ends up dialing a real interface,
2716 * it won't call one that has already been called. */
2717 if (strncasecmp(cur->interface, "Local/", 6)) {
2718 if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) {
2719 ao2_ref(cur, -1);
2720 ast_mutex_unlock(&qe->parent->lock);
2721 if (use_weight)
2722 AST_LIST_UNLOCK(&queues);
2723 free(tmp);
2724 goto out;
2726 strcpy(di->interface, cur->interface);
2728 AST_LIST_LOCK(dialed_interfaces);
2729 AST_LIST_INSERT_TAIL(dialed_interfaces, di, list);
2730 AST_LIST_UNLOCK(dialed_interfaces);
2733 tmp->stillgoing = -1;
2734 tmp->member = cur;
2735 tmp->oldstatus = cur->status;
2736 tmp->lastcall = cur->lastcall;
2737 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
2738 /* Special case: If we ring everyone, go ahead and ring them, otherwise
2739 just calculate their metric for the appropriate strategy */
2740 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
2741 /* Put them in the list of outgoing thingies... We're ready now.
2742 XXX If we're forcibly removed, these outgoing calls won't get
2743 hung up XXX */
2744 tmp->q_next = outgoing;
2745 outgoing = tmp;
2746 /* If this line is up, don't try anybody else */
2747 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
2748 break;
2749 } else {
2750 ao2_ref(cur, -1);
2751 free(tmp);
2754 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout))
2755 to = (qe->expire - now) * 1000;
2756 else
2757 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
2758 ++qe->pending;
2759 ast_mutex_unlock(&qe->parent->lock);
2760 ring_one(qe, outgoing, &numbusies);
2761 if (use_weight)
2762 AST_LIST_UNLOCK(&queues);
2763 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed);
2764 /* The ast_channel_datastore_remove() function could fail here if the
2765 * datastore was moved to another channel during a masquerade. If this is
2766 * the case, don't free the datastore here because later, when the channel
2767 * to which the datastore was moved hangs up, it will attempt to free this
2768 * datastore again, causing a crash
2770 if (datastore && !ast_channel_datastore_remove(qe->chan, datastore)) {
2771 ast_channel_datastore_free(datastore);
2773 ast_mutex_lock(&qe->parent->lock);
2774 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
2775 store_next(qe, outgoing);
2777 ast_mutex_unlock(&qe->parent->lock);
2778 peer = lpeer ? lpeer->chan : NULL;
2779 if (!peer) {
2780 qe->pending = 0;
2781 if (to) {
2782 /* Must gotten hung up */
2783 res = -1;
2784 } else {
2785 /* User exited by pressing a digit */
2786 res = digit;
2788 if (option_debug && res == -1)
2789 ast_log(LOG_DEBUG, "%s: Nobody answered.\n", qe->chan->name);
2790 } else { /* peer is valid */
2791 /* Ah ha! Someone answered within the desired timeframe. Of course after this
2792 we will always return with -1 so that it is hung up properly after the
2793 conversation. */
2794 if (!strcmp(qe->chan->tech->type, "Zap"))
2795 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2796 if (!strcmp(peer->tech->type, "Zap"))
2797 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2798 /* Update parameters for the queue */
2799 time(&now);
2800 recalc_holdtime(qe, (now - qe->start));
2801 ast_mutex_lock(&qe->parent->lock);
2802 callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel);
2803 ast_mutex_unlock(&qe->parent->lock);
2804 member = lpeer->member;
2805 /* Increment the refcount for this member, since we're going to be using it for awhile in here. */
2806 ao2_ref(member, 1);
2807 hangupcalls(outgoing, peer);
2808 outgoing = NULL;
2809 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
2810 int res2;
2812 res2 = ast_autoservice_start(qe->chan);
2813 if (!res2) {
2814 if (qe->parent->memberdelay) {
2815 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
2816 res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
2818 if (!res2 && announce) {
2819 play_file(peer, announce);
2821 if (!res2 && qe->parent->reportholdtime) {
2822 if (!play_file(peer, qe->parent->sound_reporthold)) {
2823 int holdtime;
2825 time(&now);
2826 holdtime = abs((now - qe->start) / 60);
2827 if (holdtime < 2) {
2828 play_file(peer, qe->parent->sound_lessthan);
2829 ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL);
2830 } else
2831 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
2832 play_file(peer, qe->parent->sound_minutes);
2836 res2 |= ast_autoservice_stop(qe->chan);
2837 if (peer->_softhangup) {
2838 /* Agent must have hung up */
2839 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", peer->name);
2840 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", "");
2841 if (qe->parent->eventwhencalled)
2842 manager_event(EVENT_FLAG_AGENT, "AgentDump",
2843 "Queue: %s\r\n"
2844 "Uniqueid: %s\r\n"
2845 "Channel: %s\r\n"
2846 "Member: %s\r\n"
2847 "MemberName: %s\r\n"
2848 "%s",
2849 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
2850 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
2851 ast_hangup(peer);
2852 ao2_ref(member, -1);
2853 goto out;
2854 } else if (res2) {
2855 /* Caller must have hung up just before being connected*/
2856 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
2857 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
2858 record_abandoned(qe);
2859 ast_hangup(peer);
2860 ao2_ref(member, -1);
2861 return -1;
2864 /* Stop music on hold */
2865 ast_moh_stop(qe->chan);
2866 /* If appropriate, log that we have a destination channel */
2867 if (qe->chan->cdr)
2868 ast_cdr_setdestchan(qe->chan->cdr, peer->name);
2869 /* Make sure channels are compatible */
2870 res = ast_channel_make_compatible(qe->chan, peer);
2871 if (res < 0) {
2872 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", "");
2873 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
2874 record_abandoned(qe);
2875 ast_hangup(peer);
2876 ao2_ref(member, -1);
2877 return -1;
2880 if (qe->parent->setinterfacevar)
2881 pbx_builtin_setvar_helper(qe->chan, "MEMBERINTERFACE", member->interface);
2883 /* Begin Monitoring */
2884 if (qe->parent->monfmt && *qe->parent->monfmt) {
2885 if (!qe->parent->montype) {
2886 if (option_debug)
2887 ast_log(LOG_DEBUG, "Starting Monitor as requested.\n");
2888 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
2889 if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))
2890 which = qe->chan;
2891 else
2892 which = peer;
2893 if (monitorfilename)
2894 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 );
2895 else if (qe->chan->cdr)
2896 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
2897 else {
2898 /* Last ditch effort -- no CDR, make up something */
2899 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
2900 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 );
2902 if (qe->parent->monjoin)
2903 ast_monitor_setjoinfiles(which, 1);
2904 } else {
2905 if (option_debug)
2906 ast_log(LOG_DEBUG, "Starting MixMonitor as requested.\n");
2907 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
2908 if (!monitorfilename) {
2909 if (qe->chan->cdr)
2910 ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid)-1);
2911 else
2912 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
2913 } else {
2914 ast_copy_string(tmpid2, monitorfilename, sizeof(tmpid2)-1);
2915 for (p = tmpid2; *p ; p++) {
2916 if (*p == '^' && *(p+1) == '{') {
2917 *p = '$';
2921 memset(tmpid, 0, sizeof(tmpid));
2922 pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1);
2925 monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC");
2926 monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS");
2928 if (monitor_exec) {
2929 ast_copy_string(meid2, monitor_exec, sizeof(meid2)-1);
2930 for (p = meid2; *p ; p++) {
2931 if (*p == '^' && *(p+1) == '{') {
2932 *p = '$';
2936 memset(meid, 0, sizeof(meid));
2937 pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1);
2940 snprintf(tmpid2, sizeof(tmpid2)-1, "%s.%s", tmpid, qe->parent->monfmt);
2942 mixmonapp = pbx_findapp("MixMonitor");
2944 if (strchr(tmpid2, '|')) {
2945 ast_log(LOG_WARNING, "monitor-format (in queues.conf) and MONITOR_FILENAME cannot contain a '|'! Not recording.\n");
2946 mixmonapp = NULL;
2949 if (!monitor_options)
2950 monitor_options = "";
2952 if (strchr(monitor_options, '|')) {
2953 ast_log(LOG_WARNING, "MONITOR_OPTIONS cannot contain a '|'! Not recording.\n");
2954 mixmonapp = NULL;
2957 if (mixmonapp) {
2958 if (!ast_strlen_zero(monitor_exec))
2959 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s|%s", tmpid2, monitor_options, monitor_exec);
2960 else
2961 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s", tmpid2, monitor_options);
2963 if (option_debug)
2964 ast_log(LOG_DEBUG, "Arguments being passed to MixMonitor: %s\n", mixmonargs);
2965 /* We purposely lock the CDR so that pbx_exec does not update the application data */
2966 if (qe->chan->cdr)
2967 ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
2968 ret = pbx_exec(qe->chan, mixmonapp, mixmonargs);
2969 if (qe->chan->cdr)
2970 ast_clear_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
2972 } else
2973 ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n");
2977 /* Drop out of the queue at this point, to prepare for next caller */
2978 leave_queue(qe);
2979 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
2980 if (option_debug)
2981 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
2982 ast_channel_sendurl(peer, url);
2984 if (!ast_strlen_zero(agi)) {
2985 if (option_debug)
2986 ast_log(LOG_DEBUG, "app_queue: agi=%s.\n", agi);
2987 app = pbx_findapp("agi");
2988 if (app) {
2989 agiexec = ast_strdupa(agi);
2990 ret = pbx_exec(qe->chan, app, agiexec);
2991 } else
2992 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
2994 qe->handled++;
2995 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s", (long)time(NULL) - qe->start, peer->uniqueid);
2996 if (qe->parent->eventwhencalled)
2997 manager_event(EVENT_FLAG_AGENT, "AgentConnect",
2998 "Queue: %s\r\n"
2999 "Uniqueid: %s\r\n"
3000 "Channel: %s\r\n"
3001 "Member: %s\r\n"
3002 "MemberName: %s\r\n"
3003 "Holdtime: %ld\r\n"
3004 "BridgedChannel: %s\r\n"
3005 "%s",
3006 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
3007 (long)time(NULL) - qe->start, peer->uniqueid,
3008 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
3009 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
3010 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
3011 time(&callstart);
3013 if (member->status == AST_DEVICE_NOT_INUSE)
3014 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);
3017 bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
3019 if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
3020 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld",
3021 qe->chan->exten, qe->chan->context, (long) (callstart - qe->start),
3022 (long) (time(NULL) - callstart));
3023 } else if (qe->chan->_softhangup) {
3024 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d",
3025 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
3026 if (qe->parent->eventwhencalled)
3027 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
3028 "Queue: %s\r\n"
3029 "Uniqueid: %s\r\n"
3030 "Channel: %s\r\n"
3031 "Member: %s\r\n"
3032 "MemberName: %s\r\n"
3033 "HoldTime: %ld\r\n"
3034 "TalkTime: %ld\r\n"
3035 "Reason: caller\r\n"
3036 "%s",
3037 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
3038 (long)(callstart - qe->start), (long)(time(NULL) - callstart),
3039 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
3040 } else {
3041 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d",
3042 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
3043 if (qe->parent->eventwhencalled)
3044 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
3045 "Queue: %s\r\n"
3046 "Uniqueid: %s\r\n"
3047 "Channel: %s\r\n"
3048 "MemberName: %s\r\n"
3049 "HoldTime: %ld\r\n"
3050 "TalkTime: %ld\r\n"
3051 "Reason: agent\r\n"
3052 "%s",
3053 queuename, qe->chan->uniqueid, peer->name, member->membername, (long)(callstart - qe->start),
3054 (long)(time(NULL) - callstart),
3055 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
3058 if (bridge != AST_PBX_NO_HANGUP_PEER)
3059 ast_hangup(peer);
3060 update_queue(qe->parent, member, callcompletedinsl);
3061 res = bridge ? bridge : 1;
3062 ao2_ref(member, -1);
3064 out:
3065 hangupcalls(outgoing, NULL);
3067 return res;
3070 static int wait_a_bit(struct queue_ent *qe)
3072 /* Don't need to hold the lock while we setup the outgoing calls */
3073 int retrywait = qe->parent->retry * 1000;
3075 int res = ast_waitfordigit(qe->chan, retrywait);
3076 if (res > 0 && !valid_exit(qe, res))
3077 res = 0;
3079 return res;
3082 static struct member *interface_exists(struct call_queue *q, const char *interface)
3084 struct member *mem;
3085 struct ao2_iterator mem_iter;
3087 if (!q)
3088 return NULL;
3090 mem_iter = ao2_iterator_init(q->members, 0);
3091 while ((mem = ao2_iterator_next(&mem_iter))) {
3092 if (!strcasecmp(interface, mem->interface))
3093 return mem;
3094 ao2_ref(mem, -1);
3097 return NULL;
3101 /* Dump all members in a specific queue to the database
3103 * <pm_family>/<queuename> = <interface>;<penalty>;<paused>[|...]
3106 static void dump_queue_members(struct call_queue *pm_queue)
3108 struct member *cur_member;
3109 char value[PM_MAX_LEN];
3110 int value_len = 0;
3111 int res;
3112 struct ao2_iterator mem_iter;
3114 memset(value, 0, sizeof(value));
3116 if (!pm_queue)
3117 return;
3119 mem_iter = ao2_iterator_init(pm_queue->members, 0);
3120 while ((cur_member = ao2_iterator_next(&mem_iter))) {
3121 if (!cur_member->dynamic) {
3122 ao2_ref(cur_member, -1);
3123 continue;
3126 res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s",
3127 value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername);
3129 ao2_ref(cur_member, -1);
3131 if (res != strlen(value + value_len)) {
3132 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
3133 break;
3135 value_len += res;
3138 if (value_len && !cur_member) {
3139 if (ast_db_put(pm_family, pm_queue->name, value))
3140 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
3141 } else
3142 /* Delete the entry if the queue is empty or there is an error */
3143 ast_db_del(pm_family, pm_queue->name);
3146 static int remove_from_queue(const char *queuename, const char *interface)
3148 struct call_queue *q;
3149 struct member *mem, tmpmem;
3150 int res = RES_NOSUCHQUEUE;
3152 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
3154 AST_LIST_LOCK(&queues);
3155 AST_LIST_TRAVERSE(&queues, q, list) {
3156 ast_mutex_lock(&q->lock);
3157 if (strcmp(q->name, queuename)) {
3158 ast_mutex_unlock(&q->lock);
3159 continue;
3162 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
3163 /* XXX future changes should beware of this assumption!! */
3164 if (!mem->dynamic) {
3165 res = RES_NOT_DYNAMIC;
3166 ao2_ref(mem, -1);
3167 ast_mutex_unlock(&q->lock);
3168 break;
3170 q->membercount--;
3171 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
3172 "Queue: %s\r\n"
3173 "Location: %s\r\n"
3174 "MemberName: %s\r\n",
3175 q->name, mem->interface, mem->membername);
3176 ao2_unlink(q->members, mem);
3177 ao2_ref(mem, -1);
3179 if (queue_persistent_members)
3180 dump_queue_members(q);
3182 res = RES_OKAY;
3183 } else {
3184 res = RES_EXISTS;
3186 ast_mutex_unlock(&q->lock);
3187 break;
3190 if (res == RES_OKAY)
3191 remove_from_interfaces(interface);
3193 AST_LIST_UNLOCK(&queues);
3195 return res;
3199 static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump)
3201 struct call_queue *q;
3202 struct member *new_member, *old_member;
3203 int res = RES_NOSUCHQUEUE;
3205 /* \note Ensure the appropriate realtime queue is loaded. Note that this
3206 * short-circuits if the queue is already in memory. */
3207 if (!(q = load_realtime_queue(queuename)))
3208 return res;
3210 AST_LIST_LOCK(&queues);
3212 ast_mutex_lock(&q->lock);
3213 if ((old_member = interface_exists(q, interface)) == NULL) {
3214 add_to_interfaces(interface);
3215 if ((new_member = create_queue_member(interface, membername, penalty, paused))) {
3216 new_member->dynamic = 1;
3217 ao2_link(q->members, new_member);
3218 q->membercount++;
3219 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
3220 "Queue: %s\r\n"
3221 "Location: %s\r\n"
3222 "MemberName: %s\r\n"
3223 "Membership: %s\r\n"
3224 "Penalty: %d\r\n"
3225 "CallsTaken: %d\r\n"
3226 "LastCall: %d\r\n"
3227 "Status: %d\r\n"
3228 "Paused: %d\r\n",
3229 q->name, new_member->interface, new_member->membername,
3230 "dynamic",
3231 new_member->penalty, new_member->calls, (int) new_member->lastcall,
3232 new_member->status, new_member->paused);
3234 ao2_ref(new_member, -1);
3235 new_member = NULL;
3237 if (dump)
3238 dump_queue_members(q);
3240 res = RES_OKAY;
3241 } else {
3242 res = RES_OUTOFMEMORY;
3244 } else {
3245 ao2_ref(old_member, -1);
3246 res = RES_EXISTS;
3248 ast_mutex_unlock(&q->lock);
3249 AST_LIST_UNLOCK(&queues);
3251 return res;
3254 static int set_member_paused(const char *queuename, const char *interface, int paused)
3256 int found = 0;
3257 struct call_queue *q;
3258 struct member *mem;
3260 /* Special event for when all queues are paused - individual events still generated */
3261 /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */
3262 if (ast_strlen_zero(queuename))
3263 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
3265 AST_LIST_LOCK(&queues);
3266 AST_LIST_TRAVERSE(&queues, q, list) {
3267 ast_mutex_lock(&q->lock);
3268 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
3269 if ((mem = interface_exists(q, interface))) {
3270 found++;
3271 if (mem->paused == paused)
3272 ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
3273 mem->paused = paused;
3275 if (queue_persistent_members)
3276 dump_queue_members(q);
3278 if (mem->realtime)
3279 update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0");
3281 ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", "");
3283 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
3284 "Queue: %s\r\n"
3285 "Location: %s\r\n"
3286 "MemberName: %s\r\n"
3287 "Paused: %d\r\n",
3288 q->name, mem->interface, mem->membername, paused);
3289 ao2_ref(mem, -1);
3292 ast_mutex_unlock(&q->lock);
3294 AST_LIST_UNLOCK(&queues);
3296 return found ? RESULT_SUCCESS : RESULT_FAILURE;
3299 /* Reload dynamic queue members persisted into the astdb */
3300 static void reload_queue_members(void)
3302 char *cur_ptr;
3303 char *queue_name;
3304 char *member;
3305 char *interface;
3306 char *membername = NULL;
3307 char *penalty_tok;
3308 int penalty = 0;
3309 char *paused_tok;
3310 int paused = 0;
3311 struct ast_db_entry *db_tree;
3312 struct ast_db_entry *entry;
3313 struct call_queue *cur_queue;
3314 char queue_data[PM_MAX_LEN];
3316 AST_LIST_LOCK(&queues);
3318 /* Each key in 'pm_family' is the name of a queue */
3319 db_tree = ast_db_gettree(pm_family, NULL);
3320 for (entry = db_tree; entry; entry = entry->next) {
3322 queue_name = entry->key + strlen(pm_family) + 2;
3324 AST_LIST_TRAVERSE(&queues, cur_queue, list) {
3325 ast_mutex_lock(&cur_queue->lock);
3326 if (!strcmp(queue_name, cur_queue->name))
3327 break;
3328 ast_mutex_unlock(&cur_queue->lock);
3331 if (!cur_queue)
3332 cur_queue = load_realtime_queue(queue_name);
3334 if (!cur_queue) {
3335 /* If the queue no longer exists, remove it from the
3336 * database */
3337 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
3338 ast_db_del(pm_family, queue_name);
3339 continue;
3340 } else
3341 ast_mutex_unlock(&cur_queue->lock);
3343 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN))
3344 continue;
3346 cur_ptr = queue_data;
3347 while ((member = strsep(&cur_ptr, "|"))) {
3348 if (ast_strlen_zero(member))
3349 continue;
3351 interface = strsep(&member, ";");
3352 penalty_tok = strsep(&member, ";");
3353 paused_tok = strsep(&member, ";");
3354 membername = strsep(&member, ";");
3356 if (!penalty_tok) {
3357 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
3358 break;
3360 penalty = strtol(penalty_tok, NULL, 10);
3361 if (errno == ERANGE) {
3362 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
3363 break;
3366 if (!paused_tok) {
3367 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
3368 break;
3370 paused = strtol(paused_tok, NULL, 10);
3371 if ((errno == ERANGE) || paused < 0 || paused > 1) {
3372 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
3373 break;
3375 if (ast_strlen_zero(membername))
3376 membername = interface;
3378 if (option_debug)
3379 ast_log(LOG_DEBUG, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name, interface, membername, penalty, paused);
3381 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0) == RES_OUTOFMEMORY) {
3382 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
3383 break;
3388 AST_LIST_UNLOCK(&queues);
3389 if (db_tree) {
3390 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
3391 ast_db_freetree(db_tree);
3395 static int pqm_exec(struct ast_channel *chan, void *data)
3397 struct ast_module_user *lu;
3398 char *parse;
3399 int priority_jump = 0;
3400 AST_DECLARE_APP_ARGS(args,
3401 AST_APP_ARG(queuename);
3402 AST_APP_ARG(interface);
3403 AST_APP_ARG(options);
3406 if (ast_strlen_zero(data)) {
3407 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface[|options])\n");
3408 return -1;
3411 parse = ast_strdupa(data);
3413 AST_STANDARD_APP_ARGS(args, parse);
3415 lu = ast_module_user_add(chan);
3417 if (args.options) {
3418 if (strchr(args.options, 'j'))
3419 priority_jump = 1;
3422 if (ast_strlen_zero(args.interface)) {
3423 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
3424 ast_module_user_remove(lu);
3425 return -1;
3428 if (set_member_paused(args.queuename, args.interface, 1)) {
3429 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
3430 if (priority_jump || ast_opt_priority_jumping) {
3431 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
3432 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
3433 ast_module_user_remove(lu);
3434 return 0;
3437 ast_module_user_remove(lu);
3438 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
3439 return 0;
3442 ast_module_user_remove(lu);
3443 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
3445 return 0;
3448 static int upqm_exec(struct ast_channel *chan, void *data)
3450 struct ast_module_user *lu;
3451 char *parse;
3452 int priority_jump = 0;
3453 AST_DECLARE_APP_ARGS(args,
3454 AST_APP_ARG(queuename);
3455 AST_APP_ARG(interface);
3456 AST_APP_ARG(options);
3459 if (ast_strlen_zero(data)) {
3460 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface[|options])\n");
3461 return -1;
3464 parse = ast_strdupa(data);
3466 AST_STANDARD_APP_ARGS(args, parse);
3468 lu = ast_module_user_add(chan);
3470 if (args.options) {
3471 if (strchr(args.options, 'j'))
3472 priority_jump = 1;
3475 if (ast_strlen_zero(args.interface)) {
3476 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
3477 ast_module_user_remove(lu);
3478 return -1;
3481 if (set_member_paused(args.queuename, args.interface, 0)) {
3482 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
3483 if (priority_jump || ast_opt_priority_jumping) {
3484 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
3485 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
3486 ast_module_user_remove(lu);
3487 return 0;
3490 ast_module_user_remove(lu);
3491 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
3492 return 0;
3495 ast_module_user_remove(lu);
3496 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
3498 return 0;
3501 static int rqm_exec(struct ast_channel *chan, void *data)
3503 int res=-1;
3504 struct ast_module_user *lu;
3505 char *parse, *temppos = NULL;
3506 int priority_jump = 0;
3507 AST_DECLARE_APP_ARGS(args,
3508 AST_APP_ARG(queuename);
3509 AST_APP_ARG(interface);
3510 AST_APP_ARG(options);
3514 if (ast_strlen_zero(data)) {
3515 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n");
3516 return -1;
3519 parse = ast_strdupa(data);
3521 AST_STANDARD_APP_ARGS(args, parse);
3523 lu = ast_module_user_add(chan);
3525 if (ast_strlen_zero(args.interface)) {
3526 args.interface = ast_strdupa(chan->name);
3527 temppos = strrchr(args.interface, '-');
3528 if (temppos)
3529 *temppos = '\0';
3532 if (args.options) {
3533 if (strchr(args.options, 'j'))
3534 priority_jump = 1;
3537 switch (remove_from_queue(args.queuename, args.interface)) {
3538 case RES_OKAY:
3539 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", "");
3540 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
3541 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
3542 res = 0;
3543 break;
3544 case RES_EXISTS:
3545 ast_log(LOG_DEBUG, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
3546 if (priority_jump || ast_opt_priority_jumping)
3547 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
3548 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
3549 res = 0;
3550 break;
3551 case RES_NOSUCHQUEUE:
3552 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
3553 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
3554 res = 0;
3555 break;
3556 case RES_NOT_DYNAMIC:
3557 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface);
3558 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC");
3559 res = 0;
3560 break;
3563 ast_module_user_remove(lu);
3565 return res;
3568 static int aqm_exec(struct ast_channel *chan, void *data)
3570 int res=-1;
3571 struct ast_module_user *lu;
3572 char *parse, *temppos = NULL;
3573 int priority_jump = 0;
3574 AST_DECLARE_APP_ARGS(args,
3575 AST_APP_ARG(queuename);
3576 AST_APP_ARG(interface);
3577 AST_APP_ARG(penalty);
3578 AST_APP_ARG(options);
3579 AST_APP_ARG(membername);
3581 int penalty = 0;
3583 if (ast_strlen_zero(data)) {
3584 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface]|[penalty][|options][|membername]])\n");
3585 return -1;
3588 parse = ast_strdupa(data);
3590 AST_STANDARD_APP_ARGS(args, parse);
3592 lu = ast_module_user_add(chan);
3594 if (ast_strlen_zero(args.interface)) {
3595 args.interface = ast_strdupa(chan->name);
3596 temppos = strrchr(args.interface, '-');
3597 if (temppos)
3598 *temppos = '\0';
3601 if (!ast_strlen_zero(args.penalty)) {
3602 if ((sscanf(args.penalty, "%d", &penalty) != 1) || penalty < 0) {
3603 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
3604 penalty = 0;
3608 if (args.options) {
3609 if (strchr(args.options, 'j'))
3610 priority_jump = 1;
3613 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members)) {
3614 case RES_OKAY:
3615 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", "");
3616 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
3617 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
3618 res = 0;
3619 break;
3620 case RES_EXISTS:
3621 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
3622 if (priority_jump || ast_opt_priority_jumping)
3623 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
3624 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
3625 res = 0;
3626 break;
3627 case RES_NOSUCHQUEUE:
3628 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
3629 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
3630 res = 0;
3631 break;
3632 case RES_OUTOFMEMORY:
3633 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename);
3634 break;
3637 ast_module_user_remove(lu);
3639 return res;
3642 static int ql_exec(struct ast_channel *chan, void *data)
3644 struct ast_module_user *u;
3645 char *parse;
3647 AST_DECLARE_APP_ARGS(args,
3648 AST_APP_ARG(queuename);
3649 AST_APP_ARG(uniqueid);
3650 AST_APP_ARG(membername);
3651 AST_APP_ARG(event);
3652 AST_APP_ARG(params);
3655 if (ast_strlen_zero(data)) {
3656 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo]\n");
3657 return -1;
3660 u = ast_module_user_add(chan);
3662 parse = ast_strdupa(data);
3664 AST_STANDARD_APP_ARGS(args, parse);
3666 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
3667 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
3668 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo])\n");
3669 ast_module_user_remove(u);
3670 return -1;
3673 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event,
3674 "%s", args.params ? args.params : "");
3676 ast_module_user_remove(u);
3678 return 0;
3681 /*!\brief The starting point for all queue calls
3683 * The process involved here is to
3684 * 1. Parse the options specified in the call to Queue()
3685 * 2. Join the queue
3686 * 3. Wait in a loop until it is our turn to try calling a queue member
3687 * 4. Attempt to call a queue member
3688 * 5. If 4. did not result in a bridged call, then check for between
3689 * call options such as periodic announcements etc.
3690 * 6. Try 4 again uless some condition (such as an expiration time) causes us to
3691 * exit the queue.
3693 static int queue_exec(struct ast_channel *chan, void *data)
3695 int res=-1;
3696 int ringing=0;
3697 struct ast_module_user *lu;
3698 const char *user_priority;
3699 const char *max_penalty_str;
3700 int prio;
3701 int max_penalty;
3702 enum queue_result reason = QUEUE_UNKNOWN;
3703 /* whether to exit Queue application after the timeout hits */
3704 int tries = 0;
3705 int noption = 0;
3706 char *parse;
3707 AST_DECLARE_APP_ARGS(args,
3708 AST_APP_ARG(queuename);
3709 AST_APP_ARG(options);
3710 AST_APP_ARG(url);
3711 AST_APP_ARG(announceoverride);
3712 AST_APP_ARG(queuetimeoutstr);
3713 AST_APP_ARG(agi);
3715 /* Our queue entry */
3716 struct queue_ent qe;
3718 if (ast_strlen_zero(data)) {
3719 ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL[|announceoverride[|timeout[|agi]]]]]\n");
3720 return -1;
3723 parse = ast_strdupa(data);
3724 AST_STANDARD_APP_ARGS(args, parse);
3726 lu = ast_module_user_add(chan);
3728 /* Setup our queue entry */
3729 memset(&qe, 0, sizeof(qe));
3730 qe.start = time(NULL);
3732 /* set the expire time based on the supplied timeout; */
3733 if (!ast_strlen_zero(args.queuetimeoutstr))
3734 qe.expire = qe.start + atoi(args.queuetimeoutstr);
3735 else
3736 qe.expire = 0;
3738 /* Get the priority from the variable ${QUEUE_PRIO} */
3739 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
3740 if (user_priority) {
3741 if (sscanf(user_priority, "%d", &prio) == 1) {
3742 if (option_debug)
3743 ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
3744 chan->name, prio);
3745 } else {
3746 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
3747 user_priority, chan->name);
3748 prio = 0;
3750 } else {
3751 if (option_debug > 2)
3752 ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n");
3753 prio = 0;
3756 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
3757 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
3758 if (sscanf(max_penalty_str, "%d", &max_penalty) == 1) {
3759 if (option_debug)
3760 ast_log(LOG_DEBUG, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n",
3761 chan->name, max_penalty);
3762 } else {
3763 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
3764 max_penalty_str, chan->name);
3765 max_penalty = 0;
3767 } else {
3768 max_penalty = 0;
3771 if (args.options && (strchr(args.options, 'r')))
3772 ringing = 1;
3774 if (option_debug)
3775 ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
3776 args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio);
3778 qe.chan = chan;
3779 qe.prio = prio;
3780 qe.max_penalty = max_penalty;
3781 qe.last_pos_said = 0;
3782 qe.last_pos = 0;
3783 qe.last_periodic_announce_time = time(NULL);
3784 qe.last_periodic_announce_sound = 0;
3785 qe.valid_digits = 0;
3786 if (!join_queue(args.queuename, &qe, &reason)) {
3787 int makeannouncement = 0;
3789 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", S_OR(args.url, ""),
3790 S_OR(chan->cid.cid_num, ""));
3791 check_turns:
3792 if (ringing) {
3793 ast_indicate(chan, AST_CONTROL_RINGING);
3794 } else {
3795 ast_moh_start(chan, qe.moh, NULL);
3798 /* This is the wait loop for callers 2 through maxlen */
3799 res = wait_our_turn(&qe, ringing, &reason);
3800 if (res)
3801 goto stop;
3803 for (;;) {
3804 /* This is the wait loop for the head caller*/
3805 /* To exit, they may get their call answered; */
3806 /* they may dial a digit from the queue context; */
3807 /* or, they may timeout. */
3809 enum queue_member_status stat;
3811 /* Leave if we have exceeded our queuetimeout */
3812 if (qe.expire && (time(NULL) > qe.expire)) {
3813 record_abandoned(&qe);
3814 reason = QUEUE_TIMEOUT;
3815 res = 0;
3816 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
3817 break;
3820 if (makeannouncement) {
3821 /* Make a position announcement, if enabled */
3822 if (qe.parent->announcefrequency && !ringing)
3823 if ((res = say_position(&qe)))
3824 goto stop;
3827 makeannouncement = 1;
3829 /* Make a periodic announcement, if enabled */
3830 if (qe.parent->periodicannouncefrequency && !ringing)
3831 if ((res = say_periodic_announcement(&qe)))
3832 goto stop;
3834 /* Try calling all queue members for 'timeout' seconds */
3835 res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi);
3836 if (res)
3837 goto stop;
3839 stat = get_member_status(qe.parent, qe.max_penalty);
3841 /* exit after 'timeout' cycle if 'n' option enabled */
3842 if (noption && tries >= qe.parent->membercount) {
3843 if (option_verbose > 2)
3844 ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n");
3845 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
3846 record_abandoned(&qe);
3847 reason = QUEUE_TIMEOUT;
3848 res = 0;
3849 break;
3852 /* leave the queue if no agents, if enabled */
3853 if (qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
3854 record_abandoned(&qe);
3855 reason = QUEUE_LEAVEEMPTY;
3856 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
3857 res = 0;
3858 break;
3861 /* leave the queue if no reachable agents, if enabled */
3862 if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
3863 record_abandoned(&qe);
3864 reason = QUEUE_LEAVEUNAVAIL;
3865 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
3866 res = 0;
3867 break;
3870 /* Leave if we have exceeded our queuetimeout */
3871 if (qe.expire && (time(NULL) > qe.expire)) {
3872 record_abandoned(&qe);
3873 reason = QUEUE_TIMEOUT;
3874 res = 0;
3875 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
3876 break;
3879 /* If using dynamic realtime members, we should regenerate the member list for this queue */
3880 update_realtime_members(qe.parent);
3882 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
3883 res = wait_a_bit(&qe);
3884 if (res)
3885 goto stop;
3888 /* Since this is a priority queue and
3889 * it is not sure that we are still at the head
3890 * of the queue, go and check for our turn again.
3892 if (!is_our_turn(&qe)) {
3893 if (option_debug)
3894 ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n",
3895 qe.chan->name);
3896 goto check_turns;
3900 stop:
3901 if (res) {
3902 if (res < 0) {
3903 if (!qe.handled) {
3904 record_abandoned(&qe);
3905 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON",
3906 "%d|%d|%ld", qe.pos, qe.opos,
3907 (long) time(NULL) - qe.start);
3909 res = -1;
3910 } else if (qe.valid_digits) {
3911 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY",
3912 "%s|%d", qe.digits, qe.pos);
3916 /* Don't allow return code > 0 */
3917 if (res >= 0 && res != AST_PBX_KEEPALIVE) {
3918 res = 0;
3919 if (ringing) {
3920 ast_indicate(chan, -1);
3921 } else {
3922 ast_moh_stop(chan);
3924 ast_stopstream(chan);
3926 leave_queue(&qe);
3927 if (reason != QUEUE_UNKNOWN)
3928 set_queue_result(chan, reason);
3929 } else {
3930 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
3931 set_queue_result(chan, reason);
3932 res = 0;
3934 ast_module_user_remove(lu);
3936 return res;
3939 static int queue_function_qac(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
3941 int count = 0;
3942 struct call_queue *q;
3943 struct ast_module_user *lu;
3944 struct member *m;
3945 struct ao2_iterator mem_iter;
3947 buf[0] = '\0';
3949 if (ast_strlen_zero(data)) {
3950 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
3951 return -1;
3954 lu = ast_module_user_add(chan);
3956 if ((q = load_realtime_queue(data))) {
3957 ast_mutex_lock(&q->lock);
3958 mem_iter = ao2_iterator_init(q->members, 0);
3959 while ((m = ao2_iterator_next(&mem_iter))) {
3960 /* Count the agents who are logged in and presently answering calls */
3961 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
3962 count++;
3964 ao2_ref(m, -1);
3966 ast_mutex_unlock(&q->lock);
3967 } else
3968 ast_log(LOG_WARNING, "queue %s was not found\n", data);
3970 snprintf(buf, len, "%d", count);
3971 ast_module_user_remove(lu);
3973 return 0;
3976 static int queue_function_queuewaitingcount(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
3978 int count = 0;
3979 struct call_queue *q;
3980 struct ast_module_user *lu;
3981 struct ast_variable *var = NULL;
3983 buf[0] = '\0';
3985 if (ast_strlen_zero(data)) {
3986 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
3987 return -1;
3990 lu = ast_module_user_add(chan);
3992 AST_LIST_LOCK(&queues);
3993 AST_LIST_TRAVERSE(&queues, q, list) {
3994 if (!strcasecmp(q->name, data)) {
3995 ast_mutex_lock(&q->lock);
3996 break;
3999 AST_LIST_UNLOCK(&queues);
4001 if (q) {
4002 count = q->count;
4003 ast_mutex_unlock(&q->lock);
4004 } else if ((var = ast_load_realtime("queues", "name", data, NULL))) {
4005 /* if the queue is realtime but was not found in memory, this
4006 * means that the queue had been deleted from memory since it was
4007 * "dead." This means it has a 0 waiting count
4009 count = 0;
4010 ast_variables_destroy(var);
4011 } else
4012 ast_log(LOG_WARNING, "queue %s was not found\n", data);
4014 snprintf(buf, len, "%d", count);
4015 ast_module_user_remove(lu);
4016 return 0;
4019 static int queue_function_queuememberlist(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
4021 struct ast_module_user *u;
4022 struct call_queue *q;
4023 struct member *m;
4025 /* Ensure an otherwise empty list doesn't return garbage */
4026 buf[0] = '\0';
4028 if (ast_strlen_zero(data)) {
4029 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
4030 return -1;
4033 u = ast_module_user_add(chan);
4035 AST_LIST_LOCK(&queues);
4036 AST_LIST_TRAVERSE(&queues, q, list) {
4037 if (!strcasecmp(q->name, data)) {
4038 ast_mutex_lock(&q->lock);
4039 break;
4042 AST_LIST_UNLOCK(&queues);
4044 if (q) {
4045 int buflen = 0, count = 0;
4046 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
4048 while ((m = ao2_iterator_next(&mem_iter))) {
4049 /* strcat() is always faster than printf() */
4050 if (count++) {
4051 strncat(buf + buflen, ",", len - buflen - 1);
4052 buflen++;
4054 strncat(buf + buflen, m->membername, len - buflen - 1);
4055 buflen += strlen(m->membername);
4056 /* Safeguard against overflow (negative length) */
4057 if (buflen >= len - 2) {
4058 ao2_ref(m, -1);
4059 ast_log(LOG_WARNING, "Truncating list\n");
4060 break;
4062 ao2_ref(m, -1);
4064 ast_mutex_unlock(&q->lock);
4065 } else
4066 ast_log(LOG_WARNING, "queue %s was not found\n", data);
4068 /* We should already be terminated, but let's make sure. */
4069 buf[len - 1] = '\0';
4070 ast_module_user_remove(u);
4072 return 0;
4075 static struct ast_custom_function queueagentcount_function = {
4076 .name = "QUEUEAGENTCOUNT",
4077 .synopsis = "Count number of agents answering a queue",
4078 .syntax = "QUEUEAGENTCOUNT(<queuename>)",
4079 .desc =
4080 "Returns the number of members currently associated with the specified queue.\n"
4081 "This function is deprecated. You should use QUEUE_MEMBER_COUNT() instead.\n",
4082 .read = queue_function_qac,
4085 static struct ast_custom_function queuemembercount_function = {
4086 .name = "QUEUE_MEMBER_COUNT",
4087 .synopsis = "Count number of members answering a queue",
4088 .syntax = "QUEUE_MEMBER_COUNT(<queuename>)",
4089 .desc =
4090 "Returns the number of members currently associated with the specified queue.\n",
4091 .read = queue_function_qac,
4094 static struct ast_custom_function queuewaitingcount_function = {
4095 .name = "QUEUE_WAITING_COUNT",
4096 .synopsis = "Count number of calls currently waiting in a queue",
4097 .syntax = "QUEUE_WAITING_COUNT(<queuename>)",
4098 .desc =
4099 "Returns the number of callers currently waiting in the specified queue.\n",
4100 .read = queue_function_queuewaitingcount,
4103 static struct ast_custom_function queuememberlist_function = {
4104 .name = "QUEUE_MEMBER_LIST",
4105 .synopsis = "Returns a list of interfaces on a queue",
4106 .syntax = "QUEUE_MEMBER_LIST(<queuename>)",
4107 .desc =
4108 "Returns a comma-separated list of members associated with the specified queue.\n",
4109 .read = queue_function_queuememberlist,
4112 static int reload_queues(void)
4114 struct call_queue *q;
4115 struct ast_config *cfg;
4116 char *cat, *tmp;
4117 struct ast_variable *var;
4118 struct member *cur, *newm;
4119 struct ao2_iterator mem_iter;
4120 int new;
4121 const char *general_val = NULL;
4122 char parse[80];
4123 char *interface;
4124 char *membername = NULL;
4125 int penalty;
4126 AST_DECLARE_APP_ARGS(args,
4127 AST_APP_ARG(interface);
4128 AST_APP_ARG(penalty);
4129 AST_APP_ARG(membername);
4132 if (!(cfg = ast_config_load("queues.conf"))) {
4133 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
4134 return 0;
4136 AST_LIST_LOCK(&queues);
4137 use_weight=0;
4138 /* Mark all non-realtime queues as dead for the moment */
4139 AST_LIST_TRAVERSE(&queues, q, list) {
4140 if (!q->realtime) {
4141 q->dead = 1;
4142 q->found = 0;
4146 /* Chug through config file */
4147 cat = NULL;
4148 while ((cat = ast_category_browse(cfg, cat)) ) {
4149 if (!strcasecmp(cat, "general")) {
4150 /* Initialize global settings */
4151 queue_persistent_members = 0;
4152 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
4153 queue_persistent_members = ast_true(general_val);
4154 autofill_default = 0;
4155 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill")))
4156 autofill_default = ast_true(general_val);
4157 montype_default = 0;
4158 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type")))
4159 if (!strcasecmp(general_val, "mixmonitor"))
4160 montype_default = 1;
4161 } else { /* Define queue */
4162 /* Look for an existing one */
4163 AST_LIST_TRAVERSE(&queues, q, list) {
4164 if (!strcmp(q->name, cat))
4165 break;
4167 if (!q) {
4168 /* Make one then */
4169 if (!(q = alloc_queue(cat))) {
4170 /* TODO: Handle memory allocation failure */
4172 new = 1;
4173 } else
4174 new = 0;
4175 if (q) {
4176 if (!new)
4177 ast_mutex_lock(&q->lock);
4178 /* Check if a queue with this name already exists */
4179 if (q->found) {
4180 ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", cat);
4181 if (!new)
4182 ast_mutex_unlock(&q->lock);
4183 continue;
4185 /* Re-initialize the queue, and clear statistics */
4186 init_queue(q);
4187 clear_queue(q);
4188 mem_iter = ao2_iterator_init(q->members, 0);
4189 while ((cur = ao2_iterator_next(&mem_iter))) {
4190 if (!cur->dynamic) {
4191 cur->delme = 1;
4193 ao2_ref(cur, -1);
4195 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
4196 if (!strcasecmp(var->name, "member")) {
4197 struct member tmpmem;
4198 membername = NULL;
4200 /* Add a new member */
4201 ast_copy_string(parse, var->value, sizeof(parse));
4203 AST_NONSTANDARD_APP_ARGS(args, parse, ',');
4205 interface = args.interface;
4206 if (!ast_strlen_zero(args.penalty)) {
4207 tmp = args.penalty;
4208 while (*tmp && *tmp < 33) tmp++;
4209 penalty = atoi(tmp);
4210 if (penalty < 0) {
4211 penalty = 0;
4213 } else
4214 penalty = 0;
4216 if (!ast_strlen_zero(args.membername)) {
4217 membername = args.membername;
4218 while (*membername && *membername < 33) membername++;
4221 /* Find the old position in the list */
4222 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
4223 cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK);
4225 newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0);
4226 ao2_link(q->members, newm);
4227 ao2_ref(newm, -1);
4228 newm = NULL;
4230 if (cur)
4231 ao2_ref(cur, -1);
4232 else {
4233 /* Add them to the master int list if necessary */
4234 add_to_interfaces(interface);
4235 q->membercount++;
4237 } else {
4238 queue_set_param(q, var->name, var->value, var->lineno, 1);
4242 /* Free remaining members marked as delme */
4243 mem_iter = ao2_iterator_init(q->members, 0);
4244 while ((cur = ao2_iterator_next(&mem_iter))) {
4245 if (! cur->delme) {
4246 ao2_ref(cur, -1);
4247 continue;
4250 q->membercount--;
4251 ao2_unlink(q->members, cur);
4252 remove_from_interfaces(cur->interface);
4253 ao2_ref(cur, -1);
4256 if (q->strategy == QUEUE_STRATEGY_ROUNDROBIN)
4257 rr_dep_warning();
4259 if (new) {
4260 AST_LIST_INSERT_HEAD(&queues, q, list);
4261 } else
4262 ast_mutex_unlock(&q->lock);
4266 ast_config_destroy(cfg);
4267 AST_LIST_TRAVERSE_SAFE_BEGIN(&queues, q, list) {
4268 if (q->dead) {
4269 AST_LIST_REMOVE_CURRENT(&queues, list);
4270 if (!q->count)
4271 destroy_queue(q);
4272 else
4273 ast_log(LOG_DEBUG, "XXX Leaking a little memory :( XXX\n");
4274 } else {
4275 ast_mutex_lock(&q->lock);
4276 mem_iter = ao2_iterator_init(q->members, 0);
4277 while ((cur = ao2_iterator_next(&mem_iter))) {
4278 if (cur->dynamic)
4279 q->membercount++;
4280 cur->status = ast_device_state(cur->interface);
4281 ao2_ref(cur, -1);
4283 ast_mutex_unlock(&q->lock);
4286 AST_LIST_TRAVERSE_SAFE_END;
4287 AST_LIST_UNLOCK(&queues);
4288 return 1;
4291 static int __queues_show(struct mansession *s, int manager, int fd, int argc, char **argv)
4293 struct call_queue *q;
4294 struct queue_ent *qe;
4295 struct member *mem;
4296 int pos, queue_show;
4297 time_t now;
4298 char max_buf[80];
4299 char *max;
4300 size_t max_left;
4301 float sl = 0;
4302 char *term = manager ? "\r\n" : "\n";
4303 struct ao2_iterator mem_iter;
4305 time(&now);
4306 if (argc == 2)
4307 queue_show = 0;
4308 else if (argc == 3)
4309 queue_show = 1;
4310 else
4311 return RESULT_SHOWUSAGE;
4313 /* We only want to load realtime queues when a specific queue is asked for. */
4314 if (queue_show)
4315 load_realtime_queue(argv[2]);
4317 AST_LIST_LOCK(&queues);
4318 if (AST_LIST_EMPTY(&queues)) {
4319 AST_LIST_UNLOCK(&queues);
4320 if (queue_show) {
4321 if (s)
4322 astman_append(s, "No such queue: %s.%s",argv[2], term);
4323 else
4324 ast_cli(fd, "No such queue: %s.%s",argv[2], term);
4325 } else {
4326 if (s)
4327 astman_append(s, "No queues.%s", term);
4328 else
4329 ast_cli(fd, "No queues.%s", term);
4331 return RESULT_SUCCESS;
4333 AST_LIST_TRAVERSE(&queues, q, list) {
4334 ast_mutex_lock(&q->lock);
4335 if (queue_show) {
4336 if (strcasecmp(q->name, argv[2]) != 0) {
4337 ast_mutex_unlock(&q->lock);
4338 if (!AST_LIST_NEXT(q, list)) {
4339 ast_cli(fd, "No such queue: %s.%s",argv[2], term);
4340 break;
4342 continue;
4345 max_buf[0] = '\0';
4346 max = max_buf;
4347 max_left = sizeof(max_buf);
4348 if (q->maxlen)
4349 ast_build_string(&max, &max_left, "%d", q->maxlen);
4350 else
4351 ast_build_string(&max, &max_left, "unlimited");
4352 sl = 0;
4353 if (q->callscompleted > 0)
4354 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
4355 if (s)
4356 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",
4357 q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->weight,
4358 q->callscompleted, q->callsabandoned,sl,q->servicelevel, term);
4359 else
4360 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",
4361 q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->weight, q->callscompleted, q->callsabandoned,sl,q->servicelevel, term);
4362 if (ao2_container_count(q->members)) {
4363 if (s)
4364 astman_append(s, " Members: %s", term);
4365 else
4366 ast_cli(fd, " Members: %s", term);
4367 mem_iter = ao2_iterator_init(q->members, 0);
4368 while ((mem = ao2_iterator_next(&mem_iter))) {
4369 max_buf[0] = '\0';
4370 max = max_buf;
4371 max_left = sizeof(max_buf);
4372 if (mem->penalty)
4373 ast_build_string(&max, &max_left, " with penalty %d", mem->penalty);
4374 if (mem->dynamic)
4375 ast_build_string(&max, &max_left, " (dynamic)");
4376 if (mem->realtime)
4377 ast_build_string(&max, &max_left, " (realtime)");
4378 if (mem->paused)
4379 ast_build_string(&max, &max_left, " (paused)");
4380 ast_build_string(&max, &max_left, " (%s)", devstate2str(mem->status));
4381 if (mem->calls) {
4382 ast_build_string(&max, &max_left, " has taken %d calls (last was %ld secs ago)",
4383 mem->calls, (long) (time(NULL) - mem->lastcall));
4384 } else
4385 ast_build_string(&max, &max_left, " has taken no calls yet");
4386 if (s)
4387 astman_append(s, " %s%s%s", mem->membername, max_buf, term);
4388 else
4389 ast_cli(fd, " %s%s%s", mem->membername, max_buf, term);
4390 ao2_ref(mem, -1);
4392 } else if (s)
4393 astman_append(s, " No Members%s", term);
4394 else
4395 ast_cli(fd, " No Members%s", term);
4396 if (q->head) {
4397 pos = 1;
4398 if (s)
4399 astman_append(s, " Callers: %s", term);
4400 else
4401 ast_cli(fd, " Callers: %s", term);
4402 for (qe = q->head; qe; qe = qe->next) {
4403 if (s)
4404 astman_append(s, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s",
4405 pos++, qe->chan->name, (long) (now - qe->start) / 60,
4406 (long) (now - qe->start) % 60, qe->prio, term);
4407 else
4408 ast_cli(fd, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s", pos++,
4409 qe->chan->name, (long) (now - qe->start) / 60,
4410 (long) (now - qe->start) % 60, qe->prio, term);
4412 } else if (s)
4413 astman_append(s, " No Callers%s", term);
4414 else
4415 ast_cli(fd, " No Callers%s", term);
4416 if (s)
4417 astman_append(s, "%s", term);
4418 else
4419 ast_cli(fd, "%s", term);
4420 ast_mutex_unlock(&q->lock);
4421 if (queue_show)
4422 break;
4424 AST_LIST_UNLOCK(&queues);
4425 return RESULT_SUCCESS;
4428 static int queue_show(int fd, int argc, char **argv)
4430 return __queues_show(NULL, 0, fd, argc, argv);
4433 static char *complete_queue(const char *line, const char *word, int pos, int state)
4435 struct call_queue *q;
4436 char *ret = NULL;
4437 int which = 0;
4438 int wordlen = strlen(word);
4440 AST_LIST_LOCK(&queues);
4441 AST_LIST_TRAVERSE(&queues, q, list) {
4442 if (!strncasecmp(word, q->name, wordlen) && ++which > state) {
4443 ret = ast_strdup(q->name);
4444 break;
4447 AST_LIST_UNLOCK(&queues);
4449 return ret;
4452 static char *complete_queue_show(const char *line, const char *word, int pos, int state)
4454 if (pos == 2)
4455 return complete_queue(line, word, pos, state);
4456 return NULL;
4459 /*!\brief callback to display queues status in manager
4460 \addtogroup Group_AMI
4462 static int manager_queues_show(struct mansession *s, const struct message *m)
4464 char *a[] = { "queue", "show" };
4466 __queues_show(s, 1, -1, 2, a);
4467 astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */
4469 return RESULT_SUCCESS;
4472 /* Dump queue status */
4473 static int manager_queues_status(struct mansession *s, const struct message *m)
4475 time_t now;
4476 int pos;
4477 const char *id = astman_get_header(m,"ActionID");
4478 const char *queuefilter = astman_get_header(m,"Queue");
4479 const char *memberfilter = astman_get_header(m,"Member");
4480 char idText[256] = "";
4481 struct call_queue *q;
4482 struct queue_ent *qe;
4483 float sl = 0;
4484 struct member *mem;
4485 struct ao2_iterator mem_iter;
4487 astman_send_ack(s, m, "Queue status will follow");
4488 time(&now);
4489 AST_LIST_LOCK(&queues);
4490 if (!ast_strlen_zero(id))
4491 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
4493 AST_LIST_TRAVERSE(&queues, q, list) {
4494 ast_mutex_lock(&q->lock);
4496 /* List queue properties */
4497 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
4498 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0);
4499 astman_append(s, "Event: QueueParams\r\n"
4500 "Queue: %s\r\n"
4501 "Max: %d\r\n"
4502 "Calls: %d\r\n"
4503 "Holdtime: %d\r\n"
4504 "Completed: %d\r\n"
4505 "Abandoned: %d\r\n"
4506 "ServiceLevel: %d\r\n"
4507 "ServicelevelPerf: %2.1f\r\n"
4508 "Weight: %d\r\n"
4509 "%s"
4510 "\r\n",
4511 q->name, q->maxlen, q->count, q->holdtime, q->callscompleted,
4512 q->callsabandoned, q->servicelevel, sl, q->weight, idText);
4513 /* List Queue Members */
4514 mem_iter = ao2_iterator_init(q->members, 0);
4515 while ((mem = ao2_iterator_next(&mem_iter))) {
4516 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter)) {
4517 astman_append(s, "Event: QueueMember\r\n"
4518 "Queue: %s\r\n"
4519 "Name: %s\r\n"
4520 "Location: %s\r\n"
4521 "Membership: %s\r\n"
4522 "Penalty: %d\r\n"
4523 "CallsTaken: %d\r\n"
4524 "LastCall: %d\r\n"
4525 "Status: %d\r\n"
4526 "Paused: %d\r\n"
4527 "%s"
4528 "\r\n",
4529 q->name, mem->membername, mem->interface, mem->dynamic ? "dynamic" : "static",
4530 mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText);
4532 ao2_ref(mem, -1);
4534 /* List Queue Entries */
4535 pos = 1;
4536 for (qe = q->head; qe; qe = qe->next) {
4537 astman_append(s, "Event: QueueEntry\r\n"
4538 "Queue: %s\r\n"
4539 "Position: %d\r\n"
4540 "Channel: %s\r\n"
4541 "CallerID: %s\r\n"
4542 "CallerIDName: %s\r\n"
4543 "Wait: %ld\r\n"
4544 "%s"
4545 "\r\n",
4546 q->name, pos++, qe->chan->name,
4547 S_OR(qe->chan->cid.cid_num, "unknown"),
4548 S_OR(qe->chan->cid.cid_name, "unknown"),
4549 (long) (now - qe->start), idText);
4552 ast_mutex_unlock(&q->lock);
4555 astman_append(s,
4556 "Event: QueueStatusComplete\r\n"
4557 "%s"
4558 "\r\n",idText);
4560 AST_LIST_UNLOCK(&queues);
4563 return RESULT_SUCCESS;
4566 static int manager_add_queue_member(struct mansession *s, const struct message *m)
4568 const char *queuename, *interface, *penalty_s, *paused_s, *membername;
4569 int paused, penalty = 0;
4571 queuename = astman_get_header(m, "Queue");
4572 interface = astman_get_header(m, "Interface");
4573 penalty_s = astman_get_header(m, "Penalty");
4574 paused_s = astman_get_header(m, "Paused");
4575 membername = astman_get_header(m, "MemberName");
4577 if (ast_strlen_zero(queuename)) {
4578 astman_send_error(s, m, "'Queue' not specified.");
4579 return 0;
4582 if (ast_strlen_zero(interface)) {
4583 astman_send_error(s, m, "'Interface' not specified.");
4584 return 0;
4587 if (ast_strlen_zero(penalty_s))
4588 penalty = 0;
4589 else if (sscanf(penalty_s, "%d", &penalty) != 1 || penalty < 0)
4590 penalty = 0;
4592 if (ast_strlen_zero(paused_s))
4593 paused = 0;
4594 else
4595 paused = abs(ast_true(paused_s));
4597 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members)) {
4598 case RES_OKAY:
4599 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", "");
4600 astman_send_ack(s, m, "Added interface to queue");
4601 break;
4602 case RES_EXISTS:
4603 astman_send_error(s, m, "Unable to add interface: Already there");
4604 break;
4605 case RES_NOSUCHQUEUE:
4606 astman_send_error(s, m, "Unable to add interface to queue: No such queue");
4607 break;
4608 case RES_OUTOFMEMORY:
4609 astman_send_error(s, m, "Out of memory");
4610 break;
4613 return 0;
4616 static int manager_remove_queue_member(struct mansession *s, const struct message *m)
4618 const char *queuename, *interface;
4620 queuename = astman_get_header(m, "Queue");
4621 interface = astman_get_header(m, "Interface");
4623 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
4624 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
4625 return 0;
4628 switch (remove_from_queue(queuename, interface)) {
4629 case RES_OKAY:
4630 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
4631 astman_send_ack(s, m, "Removed interface from queue");
4632 break;
4633 case RES_EXISTS:
4634 astman_send_error(s, m, "Unable to remove interface: Not there");
4635 break;
4636 case RES_NOSUCHQUEUE:
4637 astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
4638 break;
4639 case RES_OUTOFMEMORY:
4640 astman_send_error(s, m, "Out of memory");
4641 break;
4642 case RES_NOT_DYNAMIC:
4643 astman_send_error(s, m, "Member not dynamic");
4644 break;
4647 return 0;
4650 static int manager_pause_queue_member(struct mansession *s, const struct message *m)
4652 const char *queuename, *interface, *paused_s;
4653 int paused;
4655 interface = astman_get_header(m, "Interface");
4656 paused_s = astman_get_header(m, "Paused");
4657 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */
4659 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
4660 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
4661 return 0;
4664 paused = abs(ast_true(paused_s));
4666 if (set_member_paused(queuename, interface, paused))
4667 astman_send_error(s, m, "Interface not found");
4668 else
4669 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
4670 return 0;
4673 static int handle_queue_add_member(int fd, int argc, char *argv[])
4675 char *queuename, *interface, *membername = NULL;
4676 int penalty;
4678 if ((argc != 6) && (argc != 8) && (argc != 10)) {
4679 return RESULT_SHOWUSAGE;
4680 } else if (strcmp(argv[4], "to")) {
4681 return RESULT_SHOWUSAGE;
4682 } else if ((argc == 8) && strcmp(argv[6], "penalty")) {
4683 return RESULT_SHOWUSAGE;
4684 } else if ((argc == 10) && strcmp(argv[8], "as")) {
4685 return RESULT_SHOWUSAGE;
4688 queuename = argv[5];
4689 interface = argv[3];
4690 if (argc >= 8) {
4691 if (sscanf(argv[7], "%d", &penalty) == 1) {
4692 if (penalty < 0) {
4693 ast_cli(fd, "Penalty must be >= 0\n");
4694 penalty = 0;
4696 } else {
4697 ast_cli(fd, "Penalty must be an integer >= 0\n");
4698 penalty = 0;
4700 } else {
4701 penalty = 0;
4704 if (argc >= 10) {
4705 membername = argv[9];
4708 switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members)) {
4709 case RES_OKAY:
4710 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
4711 ast_cli(fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
4712 return RESULT_SUCCESS;
4713 case RES_EXISTS:
4714 ast_cli(fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
4715 return RESULT_FAILURE;
4716 case RES_NOSUCHQUEUE:
4717 ast_cli(fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
4718 return RESULT_FAILURE;
4719 case RES_OUTOFMEMORY:
4720 ast_cli(fd, "Out of memory\n");
4721 return RESULT_FAILURE;
4722 default:
4723 return RESULT_FAILURE;
4727 static char *complete_queue_add_member(const char *line, const char *word, int pos, int state)
4729 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
4730 switch (pos) {
4731 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
4732 return NULL;
4733 case 4: /* only one possible match, "to" */
4734 return state == 0 ? ast_strdup("to") : NULL;
4735 case 5: /* <queue> */
4736 return complete_queue(line, word, pos, state);
4737 case 6: /* only one possible match, "penalty" */
4738 return state == 0 ? ast_strdup("penalty") : NULL;
4739 case 7:
4740 if (state < 100) { /* 0-99 */
4741 char *num;
4742 if ((num = ast_malloc(3))) {
4743 sprintf(num, "%d", state);
4745 return num;
4746 } else {
4747 return NULL;
4749 case 8: /* only one possible match, "as" */
4750 return state == 0 ? ast_strdup("as") : NULL;
4751 case 9: /* Don't attempt to complete name of member (infinite possibilities) */
4752 return NULL;
4753 default:
4754 return NULL;
4758 static int handle_queue_remove_member(int fd, int argc, char *argv[])
4760 char *queuename, *interface;
4762 if (argc != 6) {
4763 return RESULT_SHOWUSAGE;
4764 } else if (strcmp(argv[4], "from")) {
4765 return RESULT_SHOWUSAGE;
4768 queuename = argv[5];
4769 interface = argv[3];
4771 switch (remove_from_queue(queuename, interface)) {
4772 case RES_OKAY:
4773 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
4774 ast_cli(fd, "Removed interface '%s' from queue '%s'\n", interface, queuename);
4775 return RESULT_SUCCESS;
4776 case RES_EXISTS:
4777 ast_cli(fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
4778 return RESULT_FAILURE;
4779 case RES_NOSUCHQUEUE:
4780 ast_cli(fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
4781 return RESULT_FAILURE;
4782 case RES_OUTOFMEMORY:
4783 ast_cli(fd, "Out of memory\n");
4784 return RESULT_FAILURE;
4785 case RES_NOT_DYNAMIC:
4786 ast_cli(fd, "Member not dynamic\n");
4787 return RESULT_FAILURE;
4788 default:
4789 return RESULT_FAILURE;
4793 static char *complete_queue_remove_member(const char *line, const char *word, int pos, int state)
4795 int which = 0;
4796 struct call_queue *q;
4797 struct member *m;
4798 struct ao2_iterator mem_iter;
4800 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
4801 if (pos > 5 || pos < 3)
4802 return NULL;
4803 if (pos == 4) /* only one possible match, 'from' */
4804 return state == 0 ? ast_strdup("from") : NULL;
4806 if (pos == 5) /* No need to duplicate code */
4807 return complete_queue(line, word, pos, state);
4809 /* here is the case for 3, <member> */
4810 if (!AST_LIST_EMPTY(&queues)) { /* XXX unnecessary ? the traverse does that for us */
4811 AST_LIST_TRAVERSE(&queues, q, list) {
4812 ast_mutex_lock(&q->lock);
4813 mem_iter = ao2_iterator_init(q->members, 0);
4814 while ((m = ao2_iterator_next(&mem_iter))) {
4815 if (++which > state) {
4816 char *tmp;
4817 ast_mutex_unlock(&q->lock);
4818 tmp = ast_strdup(m->interface);
4819 ao2_ref(m, -1);
4820 return tmp;
4822 ao2_ref(m, -1);
4824 ast_mutex_unlock(&q->lock);
4828 return NULL;
4831 static char queue_show_usage[] =
4832 "Usage: queue show\n"
4833 " Provides summary information on a specified queue.\n";
4835 static char qam_cmd_usage[] =
4836 "Usage: queue add member <channel> to <queue> [penalty <penalty>]\n";
4838 static char qrm_cmd_usage[] =
4839 "Usage: queue remove member <channel> from <queue>\n";
4841 static struct ast_cli_entry cli_show_queue_deprecated = {
4842 { "show", "queue", NULL },
4843 queue_show, NULL,
4844 NULL, complete_queue_show };
4846 static struct ast_cli_entry cli_add_queue_member_deprecated = {
4847 { "add", "queue", "member", NULL },
4848 handle_queue_add_member, NULL,
4849 NULL, complete_queue_add_member };
4851 static struct ast_cli_entry cli_remove_queue_member_deprecated = {
4852 { "remove", "queue", "member", NULL },
4853 handle_queue_remove_member, NULL,
4854 NULL, complete_queue_remove_member };
4856 static struct ast_cli_entry cli_queue[] = {
4857 /* Deprecated */
4858 { { "show", "queues", NULL },
4859 queue_show, NULL,
4860 NULL, NULL },
4862 { { "queue", "show", NULL },
4863 queue_show, "Show status of a specified queue",
4864 queue_show_usage, complete_queue_show, &cli_show_queue_deprecated },
4866 { { "queue", "add", "member", NULL },
4867 handle_queue_add_member, "Add a channel to a specified queue",
4868 qam_cmd_usage, complete_queue_add_member, &cli_add_queue_member_deprecated },
4870 { { "queue", "remove", "member", NULL },
4871 handle_queue_remove_member, "Removes a channel from a specified queue",
4872 qrm_cmd_usage, complete_queue_remove_member, &cli_remove_queue_member_deprecated },
4875 static int unload_module(void)
4877 int res;
4879 if (device_state.thread != AST_PTHREADT_NULL) {
4880 device_state.stop = 1;
4881 ast_mutex_lock(&device_state.lock);
4882 ast_cond_signal(&device_state.cond);
4883 ast_mutex_unlock(&device_state.lock);
4884 pthread_join(device_state.thread, NULL);
4887 ast_cli_unregister_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry));
4888 res = ast_manager_unregister("QueueStatus");
4889 res |= ast_manager_unregister("Queues");
4890 res |= ast_manager_unregister("QueueStatus");
4891 res |= ast_manager_unregister("QueueAdd");
4892 res |= ast_manager_unregister("QueueRemove");
4893 res |= ast_manager_unregister("QueuePause");
4894 res |= ast_unregister_application(app_aqm);
4895 res |= ast_unregister_application(app_rqm);
4896 res |= ast_unregister_application(app_pqm);
4897 res |= ast_unregister_application(app_upqm);
4898 res |= ast_unregister_application(app_ql);
4899 res |= ast_unregister_application(app);
4900 res |= ast_custom_function_unregister(&queueagentcount_function);
4901 res |= ast_custom_function_unregister(&queuemembercount_function);
4902 res |= ast_custom_function_unregister(&queuememberlist_function);
4903 res |= ast_custom_function_unregister(&queuewaitingcount_function);
4904 ast_devstate_del(statechange_queue, NULL);
4906 ast_module_user_hangup_all();
4908 clear_and_free_interfaces();
4910 return res;
4913 static int load_module(void)
4915 int res;
4917 if (!reload_queues())
4918 return AST_MODULE_LOAD_DECLINE;
4920 if (queue_persistent_members)
4921 reload_queue_members();
4923 ast_mutex_init(&device_state.lock);
4924 ast_cond_init(&device_state.cond, NULL);
4925 ast_pthread_create(&device_state.thread, NULL, device_state_thread, NULL);
4927 ast_cli_register_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry));
4928 res = ast_register_application(app, queue_exec, synopsis, descrip);
4929 res |= ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip);
4930 res |= ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip);
4931 res |= ast_register_application(app_pqm, pqm_exec, app_pqm_synopsis, app_pqm_descrip);
4932 res |= ast_register_application(app_upqm, upqm_exec, app_upqm_synopsis, app_upqm_descrip);
4933 res |= ast_register_application(app_ql, ql_exec, app_ql_synopsis, app_ql_descrip);
4934 res |= ast_manager_register("Queues", 0, manager_queues_show, "Queues");
4935 res |= ast_manager_register("QueueStatus", 0, manager_queues_status, "Queue Status");
4936 res |= ast_manager_register("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member, "Add interface to queue.");
4937 res |= ast_manager_register("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member, "Remove interface from queue.");
4938 res |= ast_manager_register("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member, "Makes a queue member temporarily unavailable");
4939 res |= ast_custom_function_register(&queueagentcount_function);
4940 res |= ast_custom_function_register(&queuemembercount_function);
4941 res |= ast_custom_function_register(&queuememberlist_function);
4942 res |= ast_custom_function_register(&queuewaitingcount_function);
4943 res |= ast_devstate_add(statechange_queue, NULL);
4945 return res;
4948 static int reload(void)
4950 reload_queues();
4951 return 0;
4954 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "True Call Queueing",
4955 .load = load_module,
4956 .unload = unload_module,
4957 .reload = reload,