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.
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
60 <depend>res_monitor</depend>
65 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
68 #include <sys/signal.h>
69 #include <netinet/in.h>
72 #include "asterisk/lock.h"
73 #include "asterisk/file.h"
74 #include "asterisk/channel.h"
75 #include "asterisk/pbx.h"
76 #include "asterisk/app.h"
77 #include "asterisk/linkedlists.h"
78 #include "asterisk/module.h"
79 #include "asterisk/translate.h"
80 #include "asterisk/say.h"
81 #include "asterisk/features.h"
82 #include "asterisk/musiconhold.h"
83 #include "asterisk/cli.h"
84 #include "asterisk/manager.h"
85 #include "asterisk/config.h"
86 #include "asterisk/monitor.h"
87 #include "asterisk/utils.h"
88 #include "asterisk/causes.h"
89 #include "asterisk/astdb.h"
90 #include "asterisk/devicestate.h"
91 #include "asterisk/stringfields.h"
92 #include "asterisk/event.h"
93 #include "asterisk/astobj2.h"
94 #include "asterisk/strings.h"
95 #include "asterisk/global_datastores.h"
96 #include "asterisk/taskprocessor.h"
97 #include "asterisk/callerid.h"
98 #include "asterisk/cel.h"
100 /* Define, to debug reference counts on queues, without debugging reference counts on queue members */
101 /* #define REF_DEBUG_ONLY_QUEUES */
104 * \par Please read before modifying this file.
105 * There are three locks which are regularly used
106 * throughout this file, the queue list lock, the lock
107 * for each individual queue, and the interface list lock.
108 * Please be extra careful to always lock in the following order
110 * 2) individual queue lock
111 * 3) interface list lock
112 * This order has sort of "evolved" over the lifetime of this
113 * application, but it is now in place this way, so please adhere
118 <application name="Queue" language="en_US">
120 Queue a call for a call queue.
123 <parameter name="queuename" required="true" />
124 <parameter name="options">
127 <para>Mark all calls as "answered elsewhere" when cancelled.</para>
130 <para>Continue in the dialplan if the callee hangs up.</para>
133 <para>data-quality (modem) call (minimum delay).</para>
136 <para>Allow <emphasis>callee</emphasis> to hang up by pressing <literal>*</literal>.</para>
139 <para>Allow <emphasis>caller</emphasis> to hang up by pressing <literal>*</literal>.</para>
142 <para>No retries on the timeout; will exit this application and
143 go to the next step.</para>
146 <para>Ignore call forward requests from queue members and do nothing
147 when they are requested.</para>
150 <para>Asterisk will ignore any connected line update requests or any redirecting party
151 update requests it may receive on this dial attempt.</para>
154 <para>Ring instead of playing MOH. Periodic Announcements are still made, if applicable.</para>
157 <para>Allow the <emphasis>called</emphasis> user to transfer the calling user.</para>
160 <para>Allow the <emphasis>calling</emphasis> user to transfer the call.</para>
163 <para>Allow the <emphasis>called</emphasis> user to write the conversation to
164 disk via Monitor.</para>
167 <para>Allow the <emphasis>calling</emphasis> user to write the conversation to
168 disk via Monitor.</para>
171 <para>Allow the <emphasis>called</emphasis> party to enable parking of the call by sending
172 the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
175 <para>Allow the <emphasis>calling</emphasis> party to enable parking of the call by sending
176 the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
179 <para>Allow the <emphasis>called</emphasis> user to write the conversation
180 to disk via MixMonitor.</para>
183 <para>Allow the <emphasis>calling</emphasis> user to write the conversation to
184 disk via MixMonitor.</para>
188 <parameter name="URL">
189 <para><replaceable>URL</replaceable> will be sent to the called party if the channel supports it.</para>
191 <parameter name="announceoverride" />
192 <parameter name="timeout">
193 <para>Will cause the queue to fail out after a specified number of
194 seconds, checked between each <filename>queues.conf</filename> <replaceable>timeout</replaceable> and
195 <replaceable>retry</replaceable> cycle.</para>
197 <parameter name="AGI">
198 <para>Will setup an AGI script to be executed on the calling party's channel once they are
199 connected to a queue member.</para>
201 <parameter name="macro">
202 <para>Will run a macro on the calling party's channel once they are connected to a queue member.</para>
204 <parameter name="gosub">
205 <para>Will run a gosub on the calling party's channel once they are connected to a queue member.</para>
207 <parameter name="rule">
208 <para>Will cause the queue's defaultrule to be overridden by the rule specified.</para>
210 <parameter name="position">
211 <para>Attempt to enter the caller into the queue at the numerical position specified. <literal>1</literal>
212 would attempt to enter the caller at the head of the queue, and <literal>3</literal> would attempt to place
213 the caller third in the queue.</para>
217 <para>In addition to transferring the call, a call may be parked and then picked
218 up by another user.</para>
219 <para>This application will return to the dialplan if the queue does not exist, or
220 any of the join options cause the caller to not enter the queue.</para>
221 <para>This application sets the following channel variable upon completion:</para>
223 <variable name="QUEUESTATUS">
224 <para>The status of the call as a text string.</para>
225 <value name="TIMEOUT" />
226 <value name="FULL" />
227 <value name="JOINEMPTY" />
228 <value name="LEAVEEMPTY" />
229 <value name="JOINUNAVAIL" />
230 <value name="LEAVEUNAVAIL" />
231 <value name="CONTINUE" />
236 <ref type="application">AddQueueMember</ref>
237 <ref type="application">RemoveQueueMember</ref>
238 <ref type="application">PauseQueueMember</ref>
239 <ref type="application">UnpauseQueueMember</ref>
240 <ref type="application">AgentLogin</ref>
241 <ref type="function">QUEUE_MEMBER_COUNT</ref>
242 <ref type="function">QUEUE_MEMBER_LIST</ref>
243 <ref type="function">QUEUE_WAITING_COUNT</ref>
246 <application name="AddQueueMember" language="en_US">
248 Dynamically adds queue members.
251 <parameter name="queuename" required="true" />
252 <parameter name="interface" />
253 <parameter name="penalty" />
254 <parameter name="options" />
255 <parameter name="membername" />
256 <parameter name="stateinterface" />
259 <para>Dynamically adds interface to an existing queue. If the interface is
260 already in the queue it will return an error.</para>
261 <para>This application sets the following channel variable upon completion:</para>
263 <variable name="AQMSTATUS">
264 <para>The status of the attempt to add a queue member as a text string.</para>
265 <value name="ADDED" />
266 <value name="MEMBERALREADY" />
267 <value name="NOSUCHQUEUE" />
272 <ref type="application">RemoveQueueMember</ref>
273 <ref type="application">PauseQueueMember</ref>
274 <ref type="application">UnpauseQueueMember</ref>
275 <ref type="application">AgentLogin</ref>
278 <application name="RemoveQueueMember" language="en_US">
280 Dynamically removes queue members.
283 <parameter name="queuename" required="true" />
284 <parameter name="interface" />
285 <parameter name="options" />
288 <para>If the interface is <emphasis>NOT</emphasis> in the queue it will return an error.</para>
289 <para>This application sets the following channel variable upon completion:</para>
291 <variable name="RQMSTATUS">
292 <value name="REMOVED" />
293 <value name="NOTINQUEUE" />
294 <value name="NOSUCHQUEUE" />
297 <para>Example: RemoveQueueMember(techsupport,SIP/3000)</para>
300 <ref type="application">Queue</ref>
301 <ref type="application">AddQueueMember</ref>
302 <ref type="application">PauseQueueMember</ref>
303 <ref type="application">UnpauseQueueMember</ref>
306 <application name="PauseQueueMember" language="en_US">
308 Pauses a queue member.
311 <parameter name="queuename" />
312 <parameter name="interface" required="true" />
313 <parameter name="options" />
314 <parameter name="reason">
315 <para>Is used to add extra information to the appropriate queue_log entries and manager events.</para>
319 <para>Pauses (blocks calls for) a queue member. The given interface will be paused in the given queue.
320 This prevents any calls from being sent from the queue to the interface until it is
321 unpaused with UnpauseQueueMember or the manager interface. If no queuename is given,
322 the interface is paused in every queue it is a member of. The application will fail if the
323 interface is not found.</para>
324 <para>This application sets the following channel variable upon completion:</para>
326 <variable name="PQMSTATUS">
327 <para>The status of the attempt to pause a queue member as a text string.</para>
328 <value name="PAUSED" />
329 <value name="NOTFOUND" />
332 <para>Example: PauseQueueMember(,SIP/3000)</para>
335 <ref type="application">UnpauseQueueMember</ref>
338 <application name="UnpauseQueueMember" language="en_US">
340 Unpauses a queue member.
343 <parameter name="queuename" />
344 <parameter name="interface" required="true" />
345 <parameter name="options" />
346 <parameter name="reason">
347 <para>Is used to add extra information to the appropriate queue_log entries and manager events.</para>
351 <para>Unpauses (resumes calls to) a queue member. This is the counterpart to <literal>PauseQueueMember()</literal>
352 and operates exactly the same way, except it unpauses instead of pausing the given interface.</para>
353 <para>This application sets the following channel variable upon completion:</para>
355 <variable name="UPQMSTATUS">
356 <para>The status of the attempt to unpause a queue member as a text string.</para>
357 <value name="UNPAUSED" />
358 <value name="NOTFOUND" />
361 <para>Example: UnpauseQueueMember(,SIP/3000)</para>
364 <ref type="application">PauseQueueMember</ref>
367 <application name="QueueLog" language="en_US">
369 Writes to the queue_log file.
372 <parameter name="queuename" required="true" />
373 <parameter name="uniqueid" required="true" />
374 <parameter name="agent" required="true" />
375 <parameter name="event" required="true" />
376 <parameter name="additionalinfo" />
379 <para>Allows you to write your own events into the queue log.</para>
380 <para>Example: QueueLog(101,${UNIQUEID},${AGENT},WENTONBREAK,600)</para>
383 <ref type="application">Queue</ref>
386 <function name="QUEUE_VARIABLES" language="en_US">
388 Return Queue information in variables.
391 <parameter name="queuename" required="true">
393 <enum name="QUEUEMAX">
394 <para>Maxmimum number of calls allowed.</para>
396 <enum name="QUEUESTRATEGY">
397 <para>The strategy of the queue.</para>
399 <enum name="QUEUECALLS">
400 <para>Number of calls currently in the queue.</para>
402 <enum name="QUEUEHOLDTIME">
403 <para>Current average hold time.</para>
405 <enum name="QUEUECOMPLETED">
406 <para>Number of completed calls for the queue.</para>
408 <enum name="QUEUEABANDONED">
409 <para>Number of abandoned calls.</para>
411 <enum name="QUEUESRVLEVEL">
412 <para>Queue service level.</para>
414 <enum name="QUEUESRVLEVELPERF">
415 <para>Current service level performance.</para>
421 <para>Makes the following queue variables available.</para>
422 <para>Returns <literal>0</literal> if queue is found and setqueuevar is defined, <literal>-1</literal> otherwise.</para>
425 <function name="QUEUE_MEMBER" language="en_US">
427 Count number of members answering a queue.
430 <parameter name="queuename" required="true" />
431 <parameter name="option" required="true">
434 <para>Returns the number of logged-in members for the specified queue.</para>
437 <para>Returns the number of logged-in members for the specified queue available to take a call.</para>
440 <para>Returns the total number of members for the specified queue.</para>
446 <para>Returns the number of members currently associated with the specified <replaceable>queuename</replaceable>.</para>
449 <function name="QUEUE_MEMBER_COUNT" language="en_US">
451 Count number of members answering a queue.
454 <parameter name="queuename" required="true" />
457 <para>Returns the number of members currently associated with the specified <replaceable>queuename</replaceable>.</para>
458 <warning><para>This function has been deprecated in favor of the <literal>QUEUE_MEMBER()</literal> function</para></warning>
461 <ref type="function">QUEUE_MEMBER_LIST</ref>
464 <function name="QUEUE_WAITING_COUNT" language="en_US">
466 Count number of calls currently waiting in a queue.
469 <parameter name="queuename" />
472 <para>Returns the number of callers currently waiting in the specified <replaceable>queuename</replaceable>.</para>
475 <function name="QUEUE_MEMBER_LIST" language="en_US">
477 Returns a list of interfaces on a queue.
480 <parameter name="queuename" required="true" />
483 <para>Returns a comma-separated list of members associated with the specified <replaceable>queuename</replaceable>.</para>
486 <ref type="function">QUEUE_MEMBER_COUNT</ref>
489 <function name="QUEUE_MEMBER_PENALTY" language="en_US">
491 Gets or sets queue members penalty.
494 <parameter name="queuename" required="true" />
495 <parameter name="interface" required="true" />
498 <para>Gets or sets queue members penalty.</para>
501 <manager name="Queues" language="en_US">
506 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
511 <manager name="QueueStatus" language="en_US">
516 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
517 <parameter name="Queue" />
518 <parameter name="Member" />
523 <manager name="QueueSummary" language="en_US">
528 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
529 <parameter name="Queue" />
534 <manager name="QueueAdd" language="en_US">
536 Add interface to queue.
539 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
540 <parameter name="Queue" required="true" />
541 <parameter name="Interface" required="true" />
542 <parameter name="Penalty" />
543 <parameter name="Paused" />
544 <parameter name="MemberName" />
545 <parameter name="StateInterface" />
550 <manager name="QueueRemove" language="en_US">
552 Remove interface from queue.
555 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
556 <parameter name="Queue" required="true" />
557 <parameter name="Interface" required="true" />
562 <manager name="QueuePause" language="en_US">
564 Makes a queue member temporarily unavailable.
567 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
568 <parameter name="Interface" required="true" />
569 <parameter name="Paused" required="true" />
570 <parameter name="Queue" />
571 <parameter name="Reason" />
576 <manager name="QueueLog" language="en_US">
578 Adds custom entry in queue_log.
581 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
582 <parameter name="Queue" required="true" />
583 <parameter name="Event" required="true" />
584 <parameter name="Uniqueid" />
585 <parameter name="Interface" />
586 <parameter name="Message" />
591 <manager name="QueuePenalty" language="en_US">
593 Set the penalty for a queue member.
596 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
597 <parameter name="Interface" required="true" />
598 <parameter name="Penalty" required="true" />
599 <parameter name="Queue" />
604 <manager name="QueueRule" language="en_US">
609 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
610 <parameter name="Rule" />
615 <manager name="QueueReload" language="en_US">
617 Reload a queue, queues, or any sub-section of a queue or queues.
620 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
621 <parameter name="Queue" />
622 <parameter name="Members">
628 <parameter name="Rules">
634 <parameter name="Parameters">
644 <manager name="QueueReset" language="en_US">
646 Reset queue statistics.
649 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
650 <parameter name="Queue" />
658 QUEUE_STRATEGY_RINGALL = 0,
659 QUEUE_STRATEGY_LEASTRECENT,
660 QUEUE_STRATEGY_FEWESTCALLS,
661 QUEUE_STRATEGY_RANDOM,
662 QUEUE_STRATEGY_RRMEMORY,
663 QUEUE_STRATEGY_LINEAR,
664 QUEUE_STRATEGY_WRANDOM
667 enum queue_reload_mask {
668 QUEUE_RELOAD_PARAMETERS = (1 << 0),
669 QUEUE_RELOAD_MEMBER = (1 << 1),
670 QUEUE_RELOAD_RULES = (1 << 2),
671 QUEUE_RESET_STATS = (1 << 3),
674 static const struct strategy {
678 { QUEUE_STRATEGY_RINGALL, "ringall" },
679 { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
680 { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
681 { QUEUE_STRATEGY_RANDOM, "random" },
682 { QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
683 { QUEUE_STRATEGY_RRMEMORY, "roundrobin" },
684 { QUEUE_STRATEGY_LINEAR, "linear" },
685 { QUEUE_STRATEGY_WRANDOM, "wrandom"},
688 static struct ast_taskprocessor *devicestate_tps;
690 #define DEFAULT_RETRY 5
691 #define DEFAULT_TIMEOUT 15
692 #define RECHECK 1 /*!< Recheck every second to see we we're at the top yet */
693 #define MAX_PERIODIC_ANNOUNCEMENTS 10 /*!< The maximum periodic announcements we can have */
694 #define DEFAULT_MIN_ANNOUNCE_FREQUENCY 15 /*!< The minimum number of seconds between position announcements \
695 The default value of 15 provides backwards compatibility */
696 #define MAX_QUEUE_BUCKETS 53
698 #define RES_OKAY 0 /*!< Action completed */
699 #define RES_EXISTS (-1) /*!< Entry already exists */
700 #define RES_OUTOFMEMORY (-2) /*!< Out of memory */
701 #define RES_NOSUCHQUEUE (-3) /*!< No such queue */
702 #define RES_NOT_DYNAMIC (-4) /*!< Member is not dynamic */
704 static char *app = "Queue";
706 static char *app_aqm = "AddQueueMember" ;
708 static char *app_rqm = "RemoveQueueMember" ;
710 static char *app_pqm = "PauseQueueMember" ;
712 static char *app_upqm = "UnpauseQueueMember" ;
714 static char *app_ql = "QueueLog" ;
716 /*! \brief Persistent Members astdb family */
717 static const char * const pm_family = "Queue/PersistentMembers";
718 /* The maximum length of each persistent member queue database entry */
719 #define PM_MAX_LEN 8192
721 /*! \brief queues.conf [general] option */
722 static int queue_persistent_members = 0;
724 /*! \brief queues.conf per-queue weight option */
725 static int use_weight = 0;
727 /*! \brief queues.conf [general] option */
728 static int autofill_default = 0;
730 /*! \brief queues.conf [general] option */
731 static int montype_default = 0;
733 /*! \brief queues.conf [general] option */
734 static int shared_lastcall = 0;
736 /*! \brief Subscription to device state change events */
737 static struct ast_event_sub *device_state_sub;
739 /*! \brief queues.conf [general] option */
740 static int update_cdr = 0;
746 QUEUE_LEAVEEMPTY = 3,
747 QUEUE_JOINUNAVAIL = 4,
748 QUEUE_LEAVEUNAVAIL = 5,
753 static const struct {
754 enum queue_result id;
756 } queue_results[] = {
757 { QUEUE_UNKNOWN, "UNKNOWN" },
758 { QUEUE_TIMEOUT, "TIMEOUT" },
759 { QUEUE_JOINEMPTY,"JOINEMPTY" },
760 { QUEUE_LEAVEEMPTY, "LEAVEEMPTY" },
761 { QUEUE_JOINUNAVAIL, "JOINUNAVAIL" },
762 { QUEUE_LEAVEUNAVAIL, "LEAVEUNAVAIL" },
763 { QUEUE_FULL, "FULL" },
764 { QUEUE_CONTINUE, "CONTINUE" },
767 enum queue_timeout_priority {
768 TIMEOUT_PRIORITY_APP,
769 TIMEOUT_PRIORITY_CONF,
772 /*! \brief We define a custom "local user" structure because we
773 * use it not only for keeping track of what is in use but
774 * also for keeping track of who we're dialing.
776 * There are two "links" defined in this structure, q_next and call_next.
777 * q_next links ALL defined callattempt structures into a linked list. call_next is
778 * a link which allows for a subset of the callattempts to be traversed. This subset
779 * is used in wait_for_answer so that irrelevant callattempts are not traversed. This
780 * also is helpful so that queue logs are always accurate in the case where a call to
781 * a member times out, especially if using the ringall strategy.
785 struct callattempt *q_next;
786 struct callattempt *call_next;
787 struct ast_channel *chan;
793 struct call_queue *lastqueue;
794 struct member *member;
795 unsigned int update_connectedline:1;
796 struct ast_party_connected_line connected;
801 struct call_queue *parent; /*!< What queue is our parent */
802 char moh[80]; /*!< Name of musiconhold to be used */
803 char announce[80]; /*!< Announcement to play for member when call is answered */
804 char context[AST_MAX_CONTEXT]; /*!< Context when user exits queue */
805 char digits[AST_MAX_EXTENSION]; /*!< Digits entered while in queue */
806 int valid_digits; /*!< Digits entered correspond to valid extension. Exited */
807 int pos; /*!< Where we are in the queue */
808 int prio; /*!< Our priority */
809 int last_pos_said; /*!< Last position we told the user */
810 time_t last_periodic_announce_time; /*!< The last time we played a periodic announcement */
811 int last_periodic_announce_sound; /*!< The last periodic announcement we made */
812 time_t last_pos; /*!< Last time we told the user their position */
813 int opos; /*!< Where we started in the queue */
814 int handled; /*!< Whether our call was handled */
815 int pending; /*!< Non-zero if we are attempting to call a member */
816 int max_penalty; /*!< Limit the members that can take this call to this penalty or lower */
817 int min_penalty; /*!< Limit the members that can take this call to this penalty or higher */
818 int linpos; /*!< If using linear strategy, what position are we at? */
819 int linwrapped; /*!< Is the linpos wrapped? */
820 time_t start; /*!< When we started holding */
821 time_t expire; /*!< When this entry should expire (time out of queue) */
822 int cancel_answered_elsewhere; /*!< Whether we should force the CAE flag on this call (C) option*/
823 struct ast_channel *chan; /*!< Our channel */
824 AST_LIST_HEAD_NOLOCK(,penalty_rule) qe_rules; /*!< Local copy of the queue's penalty rules */
825 struct penalty_rule *pr; /*!< Pointer to the next penalty rule to implement */
826 struct queue_ent *next; /*!< The next queue entry */
830 char interface[80]; /*!< Technology/Location to dial to reach this member*/
831 char state_exten[AST_MAX_EXTENSION]; /*!< Extension to get state from (if using hint) */
832 char state_context[AST_MAX_CONTEXT]; /*!< Context to use when getting state (if using hint) */
833 char state_interface[80]; /*!< Technology/Location from which to read devicestate changes */
834 char membername[80]; /*!< Member name to use in queue logs */
835 int penalty; /*!< Are we a last resort? */
836 int calls; /*!< Number of calls serviced by this member */
837 int dynamic; /*!< Are we dynamically added? */
838 int realtime; /*!< Is this member realtime? */
839 int status; /*!< Status of queue member */
840 int paused; /*!< Are we paused (not accepting calls)? */
841 time_t lastcall; /*!< When last successful call was hungup */
842 struct call_queue *lastqueue; /*!< Last queue we received a call */
843 unsigned int dead:1; /*!< Used to detect members deleted in realtime */
844 unsigned int delme:1; /*!< Flag to delete entry on reload */
845 char rt_uniqueid[80]; /*!< Unique id of realtime member entry */
848 enum empty_conditions {
849 QUEUE_EMPTY_PENALTY = (1 << 0),
850 QUEUE_EMPTY_PAUSED = (1 << 1),
851 QUEUE_EMPTY_INUSE = (1 << 2),
852 QUEUE_EMPTY_RINGING = (1 << 3),
853 QUEUE_EMPTY_UNAVAILABLE = (1 << 4),
854 QUEUE_EMPTY_INVALID = (1 << 5),
855 QUEUE_EMPTY_UNKNOWN = (1 << 6),
856 QUEUE_EMPTY_WRAPUP = (1 << 7),
859 /* values used in multi-bit flags in call_queue */
860 #define ANNOUNCEHOLDTIME_ALWAYS 1
861 #define ANNOUNCEHOLDTIME_ONCE 2
862 #define QUEUE_EVENT_VARIABLES 3
864 struct penalty_rule {
865 int time; /*!< Number of seconds that need to pass before applying this rule */
866 int max_value; /*!< The amount specified in the penalty rule for max penalty */
867 int min_value; /*!< The amount specified in the penalty rule for min penalty */
868 int max_relative; /*!< Is the max adjustment relative? 1 for relative, 0 for absolute */
869 int min_relative; /*!< Is the min adjustment relative? 1 for relative, 0 for absolute */
870 AST_LIST_ENTRY(penalty_rule) list; /*!< Next penalty_rule */
873 #define ANNOUNCEPOSITION_YES 1 /*!< We announce position */
874 #define ANNOUNCEPOSITION_NO 2 /*!< We don't announce position */
875 #define ANNOUNCEPOSITION_MORE_THAN 3 /*!< We say "Currently there are more than <limit>" */
876 #define ANNOUNCEPOSITION_LIMIT 4 /*!< We not announce position more than <limit> */
879 AST_DECLARE_STRING_FIELDS(
881 AST_STRING_FIELD(name);
882 /*! Music on Hold class */
883 AST_STRING_FIELD(moh);
884 /*! Announcement to play when call is answered */
885 AST_STRING_FIELD(announce);
887 AST_STRING_FIELD(context);
888 /*! Macro to run upon member connection */
889 AST_STRING_FIELD(membermacro);
890 /*! Gosub to run upon member connection */
891 AST_STRING_FIELD(membergosub);
892 /*! Default rule to use if none specified in call to Queue() */
893 AST_STRING_FIELD(defaultrule);
894 /*! Sound file: "Your call is now first in line" (def. queue-youarenext) */
895 AST_STRING_FIELD(sound_next);
896 /*! Sound file: "There are currently" (def. queue-thereare) */
897 AST_STRING_FIELD(sound_thereare);
898 /*! Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting) */
899 AST_STRING_FIELD(sound_calls);
900 /*! Sound file: "Currently there are more than" (def. queue-quantity1) */
901 AST_STRING_FIELD(queue_quantity1);
902 /*! Sound file: "callers waiting to speak with a representative" (def. queue-quantity2) */
903 AST_STRING_FIELD(queue_quantity2);
904 /*! Sound file: "The current estimated total holdtime is" (def. queue-holdtime) */
905 AST_STRING_FIELD(sound_holdtime);
906 /*! Sound file: "minutes." (def. queue-minutes) */
907 AST_STRING_FIELD(sound_minutes);
908 /*! Sound file: "minute." (def. queue-minute) */
909 AST_STRING_FIELD(sound_minute);
910 /*! Sound file: "seconds." (def. queue-seconds) */
911 AST_STRING_FIELD(sound_seconds);
912 /*! Sound file: "Thank you for your patience." (def. queue-thankyou) */
913 AST_STRING_FIELD(sound_thanks);
914 /*! Sound file: Custom announce for caller, no default */
915 AST_STRING_FIELD(sound_callerannounce);
916 /*! Sound file: "Hold time" (def. queue-reporthold) */
917 AST_STRING_FIELD(sound_reporthold);
919 /*! Sound files: Custom announce, no default */
920 struct ast_str *sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS];
922 unsigned int eventwhencalled:2;
923 unsigned int ringinuse:1;
924 unsigned int setinterfacevar:1;
925 unsigned int setqueuevar:1;
926 unsigned int setqueueentryvar:1;
927 unsigned int reportholdtime:1;
928 unsigned int wrapped:1;
929 unsigned int timeoutrestart:1;
930 unsigned int announceholdtime:2;
931 unsigned int announceposition:3;
933 unsigned int maskmemberstatus:1;
934 unsigned int realtime:1;
935 unsigned int found:1;
936 unsigned int relativeperiodicannounce:1;
937 enum empty_conditions joinempty;
938 enum empty_conditions leavewhenempty;
939 int announcepositionlimit; /*!< How many positions we announce? */
940 int announcefrequency; /*!< How often to announce their position */
941 int minannouncefrequency; /*!< The minimum number of seconds between position announcements (def. 15) */
942 int periodicannouncefrequency; /*!< How often to play periodic announcement */
943 int numperiodicannounce; /*!< The number of periodic announcements configured */
944 int randomperiodicannounce; /*!< Are periodic announcments randomly chosen */
945 int roundingseconds; /*!< How many seconds do we round to? */
946 int holdtime; /*!< Current avg holdtime, based on an exponential average */
947 int talktime; /*!< Current avg talktime, based on the same exponential average */
948 int callscompleted; /*!< Number of queue calls completed */
949 int callsabandoned; /*!< Number of queue calls abandoned */
950 int servicelevel; /*!< seconds setting for servicelevel*/
951 int callscompletedinsl; /*!< Number of calls answered with servicelevel*/
952 char monfmt[8]; /*!< Format to use when recording calls */
953 int montype; /*!< Monitor type Monitor vs. MixMonitor */
954 int count; /*!< How many entries */
955 int maxlen; /*!< Max number of entries */
956 int wrapuptime; /*!< Wrapup Time */
957 int penaltymemberslimit; /*!< Disregard penalty when queue has fewer than this many members */
959 int retry; /*!< Retry calling everyone after this amount of time */
960 int timeout; /*!< How long to wait for an answer */
961 int weight; /*!< Respective weight */
962 int autopause; /*!< Auto pause queue members if they fail to answer */
963 int timeoutpriority; /*!< Do we allow a fraction of the timeout to occur for a ring? */
965 /* Queue strategy things */
966 int rrpos; /*!< Round Robin - position */
967 int memberdelay; /*!< Seconds to delay connecting member to caller */
968 int autofill; /*!< Ignore the head call status and ring an available agent */
970 struct ao2_container *members; /*!< Head of the list of members */
972 * \brief Number of members _logged in_
973 * \note There will be members in the members container that are not logged
974 * in, so this can not simply be replaced with ao2_container_count().
977 struct queue_ent *head; /*!< Head of the list of callers */
978 AST_LIST_ENTRY(call_queue) list; /*!< Next call queue */
979 AST_LIST_HEAD_NOLOCK(, penalty_rule) rules; /*!< The list of penalty rules to invoke */
984 AST_LIST_HEAD_NOLOCK(,penalty_rule) rules;
985 AST_LIST_ENTRY(rule_list) list;
988 static AST_LIST_HEAD_STATIC(rule_lists, rule_list);
990 static struct ao2_container *queues;
992 static void update_realtime_members(struct call_queue *q);
993 static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
995 static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
996 /*! \brief sets the QUEUESTATUS channel variable */
997 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
1001 for (i = 0; i < ARRAY_LEN(queue_results); i++) {
1002 if (queue_results[i].id == res) {
1003 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
1009 static const char *int2strat(int strategy)
1013 for (x = 0; x < ARRAY_LEN(strategies); x++) {
1014 if (strategy == strategies[x].strategy)
1015 return strategies[x].name;
1021 static int strat2int(const char *strategy)
1025 for (x = 0; x < ARRAY_LEN(strategies); x++) {
1026 if (!strcasecmp(strategy, strategies[x].name))
1027 return strategies[x].strategy;
1033 static int queue_hash_cb(const void *obj, const int flags)
1035 const struct call_queue *q = obj;
1037 return ast_str_case_hash(q->name);
1040 static int queue_cmp_cb(void *obj, void *arg, int flags)
1042 struct call_queue *q = obj, *q2 = arg;
1043 return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0;
1046 #ifdef REF_DEBUG_ONLY_QUEUES
1047 #define queue_ref(a) __ao2_ref_debug(a,1,"",__FILE__,__LINE__,__PRETTY_FUNCTION__)
1048 #define queue_unref(a) __ao2_ref_debug(a,-1,"",__FILE__,__LINE__,__PRETTY_FUNCTION__)
1049 #define queue_t_ref(a,b) __ao2_ref_debug(a,1,b,__FILE__,__LINE__,__PRETTY_FUNCTION__)
1050 #define queue_t_unref(a,b) __ao2_ref_debug(a,-1,b,__FILE__,__LINE__,__PRETTY_FUNCTION__)
1051 #define queues_t_link(c,q,tag) __ao2_link_debug(c,q,tag,__FILE__,__LINE__,__PRETTY_FUNCTION__)
1052 #define queues_t_unlink(c,q,tag) __ao2_unlink_debug(c,q,tag,__FILE__,__LINE__,__PRETTY_FUNCTION__)
1054 #define queue_t_ref(a,b) queue_ref(a)
1055 #define queue_t_unref(a,b) queue_unref(a)
1056 #define queues_t_link(c,q,tag) ao2_t_link(c,q,tag)
1057 #define queues_t_unlink(c,q,tag) ao2_t_unlink(c,q,tag)
1058 static inline struct call_queue *queue_ref(struct call_queue *q)
1064 static inline struct call_queue *queue_unref(struct call_queue *q)
1071 /*! \brief Set variables of queue */
1072 static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
1074 char interfacevar[256]="";
1077 if (q->setqueuevar) {
1079 if (q->callscompleted > 0)
1080 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
1082 snprintf(interfacevar, sizeof(interfacevar),
1083 "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
1084 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned, q->servicelevel, sl);
1086 pbx_builtin_setvar_multiple(chan, interfacevar);
1090 /*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
1091 static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
1093 struct queue_ent *cur;
1106 /* every queue_ent must have a reference to it's parent call_queue, this
1107 * reference does not go away until the end of the queue_ent's life, meaning
1108 * that even when the queue_ent leaves the call_queue this ref must remain. */
1111 new->pos = ++(*pos);
1115 /*! \brief Check if members are available
1117 * This function checks to see if members are available to be called. If any member
1118 * is available, the function immediately returns 0. If no members are available,
1119 * then -1 is returned.
1121 static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, enum empty_conditions conditions)
1123 struct member *member;
1124 struct ao2_iterator mem_iter;
1127 mem_iter = ao2_iterator_init(q->members, 0);
1128 for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
1129 if ((max_penalty && (member->penalty > max_penalty)) || (min_penalty && (member->penalty < min_penalty))) {
1130 if (conditions & QUEUE_EMPTY_PENALTY) {
1131 ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
1136 switch (member->status) {
1137 case AST_DEVICE_INVALID:
1138 if (conditions & QUEUE_EMPTY_INVALID) {
1139 ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername);
1142 case AST_DEVICE_UNAVAILABLE:
1143 if (conditions & QUEUE_EMPTY_UNAVAILABLE) {
1144 ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername);
1147 case AST_DEVICE_INUSE:
1148 if (conditions & QUEUE_EMPTY_INUSE) {
1149 ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername);
1152 case AST_DEVICE_UNKNOWN:
1153 if (conditions & QUEUE_EMPTY_UNKNOWN) {
1154 ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername);
1158 if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) {
1159 ast_debug(4, "%s is unavailable because he is paused'\n", member->membername);
1161 } else if ((conditions & QUEUE_EMPTY_WRAPUP) && member->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < member->lastcall)) {
1162 ast_debug(4, "%s is unavailable because it has only been %d seconds since his last call (wrapup time is %d)\n", member->membername, (int) (time(NULL) - member->lastcall), q->wrapuptime);
1166 ao2_ref(member, -1);
1167 ao2_iterator_destroy(&mem_iter);
1168 ast_debug(4, "%s is available.\n", member->membername);
1174 ao2_iterator_destroy(&mem_iter);
1180 struct statechange {
1181 AST_LIST_ENTRY(statechange) entry;
1186 /*! \brief set a member's status based on device state of that member's state_interface.
1188 * Lock interface list find sc, iterate through each queues queue_member list for member to
1189 * update state inside queues
1191 static int update_status(struct call_queue *q, struct member *m, const int status)
1195 if (q->maskmemberstatus)
1198 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
1201 "MemberName: %s\r\n"
1202 "Membership: %s\r\n"
1204 "CallsTaken: %d\r\n"
1208 q->name, m->interface, m->membername, m->dynamic ? "dynamic" : m->realtime ? "realtime" : "static",
1209 m->penalty, m->calls, (int)m->lastcall, m->status, m->paused
1215 /*! \brief set a member's status based on device state of that member's interface*/
1216 static int handle_statechange(void *datap)
1218 struct statechange *sc = datap;
1219 struct ao2_iterator miter, qiter;
1221 struct call_queue *q;
1222 char interface[80], *slash_pos;
1225 qiter = ao2_iterator_init(queues, 0);
1226 while ((q = ao2_t_iterator_next(&qiter, "Iterate over queues"))) {
1229 miter = ao2_iterator_init(q->members, 0);
1230 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
1231 ast_copy_string(interface, m->state_interface, sizeof(interface));
1233 if ((slash_pos = strchr(interface, '/')))
1234 if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/')))
1237 if (!strcasecmp(interface, sc->dev)) {
1239 update_status(q, m, sc->state);
1244 ao2_iterator_destroy(&miter);
1247 queue_t_unref(q, "Done with iterator");
1249 ao2_iterator_destroy(&qiter);
1252 ast_debug(1, "Device '%s' changed to state '%d' (%s)\n", sc->dev, sc->state, ast_devstate2str(sc->state));
1254 ast_debug(3, "Device '%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n", sc->dev, sc->state, ast_devstate2str(sc->state));
1260 static void device_state_cb(const struct ast_event *event, void *unused)
1262 enum ast_device_state state;
1264 struct statechange *sc;
1267 state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
1268 device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
1270 if (ast_strlen_zero(device)) {
1271 ast_log(LOG_ERROR, "Received invalid event that had no device IE\n");
1274 datapsize = sizeof(*sc) + strlen(device) + 1;
1275 if (!(sc = ast_calloc(1, datapsize))) {
1276 ast_log(LOG_ERROR, "failed to calloc a state change struct\n");
1280 strcpy(sc->dev, device);
1281 if (ast_taskprocessor_push(devicestate_tps, handle_statechange, sc) < 0) {
1286 /*! \brief Helper function which converts from extension state to device state values */
1287 static int extensionstate2devicestate(int state)
1290 case AST_EXTENSION_NOT_INUSE:
1291 state = AST_DEVICE_NOT_INUSE;
1293 case AST_EXTENSION_INUSE:
1294 state = AST_DEVICE_INUSE;
1296 case AST_EXTENSION_BUSY:
1297 state = AST_DEVICE_BUSY;
1299 case AST_EXTENSION_RINGING:
1300 state = AST_DEVICE_RINGING;
1302 case AST_EXTENSION_ONHOLD:
1303 state = AST_DEVICE_ONHOLD;
1305 case AST_EXTENSION_UNAVAILABLE:
1306 state = AST_DEVICE_UNAVAILABLE;
1308 case AST_EXTENSION_REMOVED:
1309 case AST_EXTENSION_DEACTIVATED:
1311 state = AST_DEVICE_INVALID;
1318 static int extension_state_cb(char *context, char *exten, enum ast_extension_states state, void *data)
1320 struct ao2_iterator miter, qiter;
1322 struct call_queue *q;
1323 int found = 0, device_state = extensionstate2devicestate(state);
1325 qiter = ao2_iterator_init(queues, 0);
1326 while ((q = ao2_t_iterator_next(&qiter, "Iterate through queues"))) {
1329 miter = ao2_iterator_init(q->members, 0);
1330 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
1331 if (!strcmp(m->state_context, context) && !strcmp(m->state_exten, exten)) {
1332 update_status(q, m, device_state);
1338 ao2_iterator_destroy(&miter);
1341 queue_t_unref(q, "Done with iterator");
1343 ao2_iterator_destroy(&qiter);
1346 ast_debug(1, "Extension '%s@%s' changed to state '%d' (%s)\n", exten, context, device_state, ast_devstate2str(device_state));
1348 ast_debug(3, "Extension '%s@%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n",
1349 exten, context, device_state, ast_devstate2str(device_state));
1355 /*! \brief Return the current state of a member */
1356 static int get_queue_member_status(struct member *cur)
1358 return ast_strlen_zero(cur->state_exten) ? ast_device_state(cur->state_interface) : extensionstate2devicestate(ast_extension_state(NULL, cur->state_context, cur->state_exten));
1361 /*! \brief allocate space for new queue member and set fields based on parameters passed */
1362 static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface)
1366 if ((cur = ao2_alloc(sizeof(*cur), NULL))) {
1367 cur->penalty = penalty;
1368 cur->paused = paused;
1369 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
1370 if (!ast_strlen_zero(state_interface))
1371 ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface));
1373 ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface));
1374 if (!ast_strlen_zero(membername))
1375 ast_copy_string(cur->membername, membername, sizeof(cur->membername));
1377 ast_copy_string(cur->membername, interface, sizeof(cur->membername));
1378 if (!strchr(cur->interface, '/'))
1379 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
1380 if (!strncmp(cur->state_interface, "hint:", 5)) {
1381 char *tmp = ast_strdupa(cur->state_interface), *context = tmp;
1382 char *exten = strsep(&context, "@") + 5;
1384 ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten));
1385 ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context));
1387 cur->status = get_queue_member_status(cur);
1394 static int compress_char(const char c)
1404 static int member_hash_fn(const void *obj, const int flags)
1406 const struct member *mem = obj;
1407 const char *chname = strchr(mem->interface, '/');
1410 chname = mem->interface;
1411 for (i = 0; i < 5 && chname[i]; i++)
1412 ret += compress_char(chname[i]) << (i * 6);
1416 static int member_cmp_fn(void *obj1, void *obj2, int flags)
1418 struct member *mem1 = obj1, *mem2 = obj2;
1419 return strcasecmp(mem1->interface, mem2->interface) ? 0 : CMP_MATCH | CMP_STOP;
1423 * \brief Initialize Queue default values.
1424 * \note the queue's lock must be held before executing this function
1426 static void init_queue(struct call_queue *q)
1429 struct penalty_rule *pr_iter;
1432 q->retry = DEFAULT_RETRY;
1433 q->timeout = DEFAULT_TIMEOUT;
1435 q->announcefrequency = 0;
1436 q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY;
1437 q->announceholdtime = 1;
1438 q->announcepositionlimit = 10; /* Default 10 positions */
1439 q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */
1440 q->roundingseconds = 0; /* Default - don't announce seconds */
1441 q->servicelevel = 0;
1443 q->setinterfacevar = 0;
1445 q->setqueueentryvar = 0;
1446 q->autofill = autofill_default;
1447 q->montype = montype_default;
1448 q->monfmt[0] = '\0';
1449 q->reportholdtime = 0;
1451 q->penaltymemberslimit = 0;
1453 q->leavewhenempty = 0;
1455 q->maskmemberstatus = 0;
1456 q->eventwhencalled = 0;
1458 q->timeoutrestart = 0;
1459 q->periodicannouncefrequency = 0;
1460 q->randomperiodicannounce = 0;
1461 q->numperiodicannounce = 0;
1462 q->timeoutpriority = TIMEOUT_PRIORITY_APP;
1464 if (q->strategy == QUEUE_STRATEGY_LINEAR)
1465 /* linear strategy depends on order, so we have to place all members in a single bucket */
1466 q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn);
1468 q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
1472 ast_string_field_set(q, sound_next, "queue-youarenext");
1473 ast_string_field_set(q, sound_thereare, "queue-thereare");
1474 ast_string_field_set(q, sound_calls, "queue-callswaiting");
1475 ast_string_field_set(q, queue_quantity1, "queue-quantity1");
1476 ast_string_field_set(q, queue_quantity2, "queue-quantity2");
1477 ast_string_field_set(q, sound_holdtime, "queue-holdtime");
1478 ast_string_field_set(q, sound_minutes, "queue-minutes");
1479 ast_string_field_set(q, sound_minute, "queue-minute");
1480 ast_string_field_set(q, sound_seconds, "queue-seconds");
1481 ast_string_field_set(q, sound_thanks, "queue-thankyou");
1482 ast_string_field_set(q, sound_reporthold, "queue-reporthold");
1484 if ((q->sound_periodicannounce[0] = ast_str_create(32)))
1485 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
1487 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
1488 if (q->sound_periodicannounce[i])
1489 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
1492 while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list)))
1496 static void clear_queue(struct call_queue *q)
1499 q->callscompleted = 0;
1500 q->callsabandoned = 0;
1501 q->callscompletedinsl = 0;
1507 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
1508 while ((mem = ao2_iterator_next(&mem_iter))) {
1512 ao2_iterator_destroy(&mem_iter);
1517 * \brief Change queue penalty by adding rule.
1519 * Check rule for errors with time or fomatting, see if rule is relative to rest
1520 * of queue, iterate list of rules to find correct insertion point, insert and return.
1521 * \retval -1 on failure
1522 * \retval 0 on success
1523 * \note Call this with the rule_lists locked
1525 static int insert_penaltychange (const char *list_name, const char *content, const int linenum)
1527 char *timestr, *maxstr, *minstr, *contentdup;
1528 struct penalty_rule *rule = NULL, *rule_iter;
1529 struct rule_list *rl_iter;
1530 int penaltychangetime, inserted = 0;
1532 if (!(rule = ast_calloc(1, sizeof(*rule)))) {
1536 contentdup = ast_strdupa(content);
1538 if (!(maxstr = strchr(contentdup, ','))) {
1539 ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum);
1545 timestr = contentdup;
1547 if ((penaltychangetime = atoi(timestr)) < 0) {
1548 ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum);
1553 rule->time = penaltychangetime;
1555 if ((minstr = strchr(maxstr,',')))
1558 /* The last check will evaluate true if either no penalty change is indicated for a given rule
1559 * OR if a min penalty change is indicated but no max penalty change is */
1560 if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') {
1561 rule->max_relative = 1;
1564 rule->max_value = atoi(maxstr);
1566 if (!ast_strlen_zero(minstr)) {
1567 if (*minstr == '+' || *minstr == '-')
1568 rule->min_relative = 1;
1569 rule->min_value = atoi(minstr);
1570 } else /*there was no minimum specified, so assume this means no change*/
1571 rule->min_relative = 1;
1573 /*We have the rule made, now we need to insert it where it belongs*/
1574 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){
1575 if (strcasecmp(rl_iter->name, list_name))
1578 AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) {
1579 if (rule->time < rule_iter->time) {
1580 AST_LIST_INSERT_BEFORE_CURRENT(rule, list);
1585 AST_LIST_TRAVERSE_SAFE_END;
1588 AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list);
1595 static void parse_empty_options(const char *value, enum empty_conditions *empty, int joinempty)
1597 char *value_copy = ast_strdupa(value);
1598 char *option = NULL;
1599 while ((option = strsep(&value_copy, ","))) {
1600 if (!strcasecmp(option, "paused")) {
1601 *empty |= QUEUE_EMPTY_PAUSED;
1602 } else if (!strcasecmp(option, "penalty")) {
1603 *empty |= QUEUE_EMPTY_PENALTY;
1604 } else if (!strcasecmp(option, "inuse")) {
1605 *empty |= QUEUE_EMPTY_INUSE;
1606 } else if (!strcasecmp(option, "ringing")) {
1607 *empty |= QUEUE_EMPTY_RINGING;
1608 } else if (!strcasecmp(option, "invalid")) {
1609 *empty |= QUEUE_EMPTY_INVALID;
1610 } else if (!strcasecmp(option, "wrapup")) {
1611 *empty |= QUEUE_EMPTY_WRAPUP;
1612 } else if (!strcasecmp(option, "unavailable")) {
1613 *empty |= QUEUE_EMPTY_UNAVAILABLE;
1614 } else if (!strcasecmp(option, "unknown")) {
1615 *empty |= QUEUE_EMPTY_UNKNOWN;
1616 } else if (!strcasecmp(option, "loose")) {
1617 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID);
1618 } else if (!strcasecmp(option, "strict")) {
1619 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED | QUEUE_EMPTY_UNAVAILABLE);
1620 } else if ((ast_false(option) && joinempty) || (ast_true(option) && !joinempty)) {
1621 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED);
1622 } else if ((ast_false(option) && !joinempty) || (ast_true(option) && joinempty)) {
1625 ast_log(LOG_WARNING, "Unknown option %s for '%s'\n", option, joinempty ? "joinempty" : "leavewhenempty");
1630 /*! \brief Configure a queue parameter.
1632 * The failunknown flag is set for config files (and static realtime) to show
1633 * errors for unknown parameters. It is cleared for dynamic realtime to allow
1634 * extra fields in the tables.
1635 * \note For error reporting, line number is passed for .conf static configuration,
1636 * for Realtime queues, linenum is -1.
1638 static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
1640 if (!strcasecmp(param, "musicclass") ||
1641 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
1642 ast_string_field_set(q, moh, val);
1643 } else if (!strcasecmp(param, "announce")) {
1644 ast_string_field_set(q, announce, val);
1645 } else if (!strcasecmp(param, "context")) {
1646 ast_string_field_set(q, context, val);
1647 } else if (!strcasecmp(param, "timeout")) {
1648 q->timeout = atoi(val);
1650 q->timeout = DEFAULT_TIMEOUT;
1651 } else if (!strcasecmp(param, "ringinuse")) {
1652 q->ringinuse = ast_true(val);
1653 } else if (!strcasecmp(param, "setinterfacevar")) {
1654 q->setinterfacevar = ast_true(val);
1655 } else if (!strcasecmp(param, "setqueuevar")) {
1656 q->setqueuevar = ast_true(val);
1657 } else if (!strcasecmp(param, "setqueueentryvar")) {
1658 q->setqueueentryvar = ast_true(val);
1659 } else if (!strcasecmp(param, "monitor-format")) {
1660 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
1661 } else if (!strcasecmp(param, "membermacro")) {
1662 ast_string_field_set(q, membermacro, val);
1663 } else if (!strcasecmp(param, "membergosub")) {
1664 ast_string_field_set(q, membergosub, val);
1665 } else if (!strcasecmp(param, "queue-youarenext")) {
1666 ast_string_field_set(q, sound_next, val);
1667 } else if (!strcasecmp(param, "queue-thereare")) {
1668 ast_string_field_set(q, sound_thereare, val);
1669 } else if (!strcasecmp(param, "queue-callswaiting")) {
1670 ast_string_field_set(q, sound_calls, val);
1671 } else if (!strcasecmp(param, "queue-quantity1")) {
1672 ast_string_field_set(q, queue_quantity1, val);
1673 } else if (!strcasecmp(param, "queue-quantity2")) {
1674 ast_string_field_set(q, queue_quantity2, val);
1675 } else if (!strcasecmp(param, "queue-holdtime")) {
1676 ast_string_field_set(q, sound_holdtime, val);
1677 } else if (!strcasecmp(param, "queue-minutes")) {
1678 ast_string_field_set(q, sound_minutes, val);
1679 } else if (!strcasecmp(param, "queue-minute")) {
1680 ast_string_field_set(q, sound_minute, val);
1681 } else if (!strcasecmp(param, "queue-seconds")) {
1682 ast_string_field_set(q, sound_seconds, val);
1683 } else if (!strcasecmp(param, "queue-thankyou")) {
1684 ast_string_field_set(q, sound_thanks, val);
1685 } else if (!strcasecmp(param, "queue-callerannounce")) {
1686 ast_string_field_set(q, sound_callerannounce, val);
1687 } else if (!strcasecmp(param, "queue-reporthold")) {
1688 ast_string_field_set(q, sound_reporthold, val);
1689 } else if (!strcasecmp(param, "announce-frequency")) {
1690 q->announcefrequency = atoi(val);
1691 } else if (!strcasecmp(param, "min-announce-frequency")) {
1692 q->minannouncefrequency = atoi(val);
1693 ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name);
1694 } else if (!strcasecmp(param, "announce-round-seconds")) {
1695 q->roundingseconds = atoi(val);
1696 /* Rounding to any other values just doesn't make sense... */
1697 if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10
1698 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) {
1700 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
1701 "using 0 instead for queue '%s' at line %d of queues.conf\n",
1702 val, param, q->name, linenum);
1704 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
1705 "using 0 instead for queue '%s'\n", val, param, q->name);
1707 q->roundingseconds=0;
1709 } else if (!strcasecmp(param, "announce-holdtime")) {
1710 if (!strcasecmp(val, "once"))
1711 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
1712 else if (ast_true(val))
1713 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
1715 q->announceholdtime = 0;
1716 } else if (!strcasecmp(param, "announce-position")) {
1717 if (!strcasecmp(val, "limit"))
1718 q->announceposition = ANNOUNCEPOSITION_LIMIT;
1719 else if (!strcasecmp(val, "more"))
1720 q->announceposition = ANNOUNCEPOSITION_MORE_THAN;
1721 else if (ast_true(val))
1722 q->announceposition = ANNOUNCEPOSITION_YES;
1724 q->announceposition = ANNOUNCEPOSITION_NO;
1725 } else if (!strcasecmp(param, "announce-position-limit")) {
1726 q->announcepositionlimit = atoi(val);
1727 } else if (!strcasecmp(param, "periodic-announce")) {
1728 if (strchr(val, ',')) {
1729 char *s, *buf = ast_strdupa(val);
1732 while ((s = strsep(&buf, ",|"))) {
1733 if (!q->sound_periodicannounce[i])
1734 q->sound_periodicannounce[i] = ast_str_create(16);
1735 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s);
1737 if (i == MAX_PERIODIC_ANNOUNCEMENTS)
1740 q->numperiodicannounce = i;
1742 ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val);
1743 q->numperiodicannounce = 1;
1745 } else if (!strcasecmp(param, "periodic-announce-frequency")) {
1746 q->periodicannouncefrequency = atoi(val);
1747 } else if (!strcasecmp(param, "relative-periodic-announce")) {
1748 q->relativeperiodicannounce = ast_true(val);
1749 } else if (!strcasecmp(param, "random-periodic-announce")) {
1750 q->randomperiodicannounce = ast_true(val);
1751 } else if (!strcasecmp(param, "retry")) {
1752 q->retry = atoi(val);
1754 q->retry = DEFAULT_RETRY;
1755 } else if (!strcasecmp(param, "wrapuptime")) {
1756 q->wrapuptime = atoi(val);
1757 } else if (!strcasecmp(param, "penaltymemberslimit")) {
1758 q->penaltymemberslimit = atoi(val);
1759 } else if (!strcasecmp(param, "autofill")) {
1760 q->autofill = ast_true(val);
1761 } else if (!strcasecmp(param, "monitor-type")) {
1762 if (!strcasecmp(val, "mixmonitor"))
1764 } else if (!strcasecmp(param, "autopause")) {
1765 q->autopause = ast_true(val);
1766 } else if (!strcasecmp(param, "maxlen")) {
1767 q->maxlen = atoi(val);
1770 } else if (!strcasecmp(param, "servicelevel")) {
1771 q->servicelevel= atoi(val);
1772 } else if (!strcasecmp(param, "strategy")) {
1775 /* We are a static queue and already have set this, no need to do it again */
1779 strategy = strat2int(val);
1781 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
1783 q->strategy = QUEUE_STRATEGY_RINGALL;
1785 if (strategy == q->strategy) {
1788 if (strategy == QUEUE_STRATEGY_LINEAR) {
1789 ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n");
1792 q->strategy = strategy;
1793 } else if (!strcasecmp(param, "joinempty")) {
1794 parse_empty_options(val, &q->joinempty, 1);
1795 } else if (!strcasecmp(param, "leavewhenempty")) {
1796 parse_empty_options(val, &q->leavewhenempty, 0);
1797 } else if (!strcasecmp(param, "eventmemberstatus")) {
1798 q->maskmemberstatus = !ast_true(val);
1799 } else if (!strcasecmp(param, "eventwhencalled")) {
1800 if (!strcasecmp(val, "vars")) {
1801 q->eventwhencalled = QUEUE_EVENT_VARIABLES;
1803 q->eventwhencalled = ast_true(val) ? 1 : 0;
1805 } else if (!strcasecmp(param, "reportholdtime")) {
1806 q->reportholdtime = ast_true(val);
1807 } else if (!strcasecmp(param, "memberdelay")) {
1808 q->memberdelay = atoi(val);
1809 } else if (!strcasecmp(param, "weight")) {
1810 q->weight = atoi(val);
1811 } else if (!strcasecmp(param, "timeoutrestart")) {
1812 q->timeoutrestart = ast_true(val);
1813 } else if (!strcasecmp(param, "defaultrule")) {
1814 ast_string_field_set(q, defaultrule, val);
1815 } else if (!strcasecmp(param, "timeoutpriority")) {
1816 if (!strcasecmp(val, "conf")) {
1817 q->timeoutpriority = TIMEOUT_PRIORITY_CONF;
1819 q->timeoutpriority = TIMEOUT_PRIORITY_APP;
1821 } else if (failunknown) {
1823 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
1824 q->name, param, linenum);
1826 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
1832 * \brief Find rt member record to update otherwise create one.
1834 * Search for member in queue, if found update penalty/paused state,
1835 * if no memeber exists create one flag it as a RT member and add to queue member list.
1837 static void rt_handle_member_record(struct call_queue *q, char *interface, const char *rt_uniqueid, const char *membername, const char *penalty_str, const char *paused_str, const char* state_interface)
1840 struct ao2_iterator mem_iter;
1846 penalty = atoi(penalty_str);
1852 paused = atoi(paused_str);
1857 /* Find member by realtime uniqueid and update */
1858 mem_iter = ao2_iterator_init(q->members, 0);
1859 while ((m = ao2_iterator_next(&mem_iter))) {
1860 if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) {
1861 m->dead = 0; /* Do not delete this one. */
1862 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
1865 if (strcasecmp(state_interface, m->state_interface)) {
1866 ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
1868 m->penalty = penalty;
1875 ao2_iterator_destroy(&mem_iter);
1877 /* Create a new member */
1879 if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) {
1882 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
1883 ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", "");
1884 ao2_link(q->members, m);
1892 /*! \brief Iterate through queue's member list and delete them */
1893 static void free_members(struct call_queue *q, int all)
1895 /* Free non-dynamic members */
1897 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
1899 while ((cur = ao2_iterator_next(&mem_iter))) {
1900 if (all || !cur->dynamic) {
1901 ao2_unlink(q->members, cur);
1906 ao2_iterator_destroy(&mem_iter);
1909 /*! \brief Free queue's member list then its string fields */
1910 static void destroy_queue(void *obj)
1912 struct call_queue *q = obj;
1916 ast_string_field_free_memory(q);
1917 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
1918 if (q->sound_periodicannounce[i])
1919 free(q->sound_periodicannounce[i]);
1921 ao2_ref(q->members, -1);
1924 static struct call_queue *alloc_queue(const char *queuename)
1926 struct call_queue *q;
1928 if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) {
1929 if (ast_string_field_init(q, 64)) {
1930 queue_t_unref(q, "String field allocation failed");
1933 ast_string_field_set(q, name, queuename);
1939 * \brief Reload a single queue via realtime.
1941 * Check for statically defined queue first, check if deleted RT queue,
1942 * check for new RT queue, if queue vars are not defined init them with defaults.
1943 * reload RT queue vars, set RT queue members dead and reload them, return finished queue.
1944 * \retval the queue,
1945 * \retval NULL if it doesn't exist.
1946 * \note Should be called with the "queues" container locked.
1948 static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
1950 struct ast_variable *v;
1951 struct call_queue *q, tmpq = {
1955 struct ao2_iterator mem_iter;
1956 char *interface = NULL;
1957 const char *tmp_name;
1959 char tmpbuf[64]; /* Must be longer than the longest queue param name. */
1961 /* Static queues override realtime. */
1962 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Check if static queue exists"))) {
1967 queue_t_unref(q, "Queue is dead; can't return it");
1970 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
1975 } else if (!member_config)
1976 /* Not found in the list, and it's not realtime ... */
1979 /* Check if queue is defined in realtime. */
1981 /* Delete queue from in-core list if it has been deleted in realtime. */
1983 /*! \note Hmm, can't seem to distinguish a DB failure from a not
1984 found condition... So we might delete an in-core queue
1985 in case of DB failure. */
1986 ast_debug(1, "Queue %s not found in realtime.\n", queuename);
1989 /* Delete if unused (else will be deleted when last caller leaves). */
1990 queues_t_unlink(queues, q, "Unused; removing from container");
1992 queue_t_unref(q, "Queue is dead; can't return it");
1997 /* Create a new queue if an in-core entry does not exist yet. */
1999 struct ast_variable *tmpvar = NULL;
2000 if (!(q = alloc_queue(queuename)))
2006 /*Before we initialize the queue, we need to set the strategy, so that linear strategy
2007 * will allocate the members properly
2009 for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) {
2010 if (!strcasecmp(tmpvar->name, "strategy")) {
2011 q->strategy = strat2int(tmpvar->value);
2012 if (q->strategy < 0) {
2013 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
2014 tmpvar->value, q->name);
2015 q->strategy = QUEUE_STRATEGY_RINGALL;
2020 /* We traversed all variables and didn't find a strategy */
2022 q->strategy = QUEUE_STRATEGY_RINGALL;
2023 queues_t_link(queues, q, "Add queue to container");
2025 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
2027 memset(tmpbuf, 0, sizeof(tmpbuf));
2028 for (v = queue_vars; v; v = v->next) {
2029 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
2030 if ((tmp = strchr(v->name, '_'))) {
2031 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
2034 while ((tmp = strchr(tmp, '_')))
2039 if (!ast_strlen_zero(v->value)) {
2040 /* Don't want to try to set the option if the value is empty */
2041 queue_set_param(q, tmp_name, v->value, -1, 0);
2045 /* Temporarily set realtime members dead so we can detect deleted ones.
2046 * Also set the membercount correctly for realtime*/
2047 mem_iter = ao2_iterator_init(q->members, 0);
2048 while ((m = ao2_iterator_next(&mem_iter))) {
2054 ao2_iterator_destroy(&mem_iter);
2056 while ((interface = ast_category_browse(member_config, interface))) {
2057 rt_handle_member_record(q, interface,
2058 ast_variable_retrieve(member_config, interface, "uniqueid"),
2059 S_OR(ast_variable_retrieve(member_config, interface, "membername"),interface),
2060 ast_variable_retrieve(member_config, interface, "penalty"),
2061 ast_variable_retrieve(member_config, interface, "paused"),
2062 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface));
2065 /* Delete all realtime members that have been deleted in DB. */
2066 mem_iter = ao2_iterator_init(q->members, 0);
2067 while ((m = ao2_iterator_next(&mem_iter))) {
2069 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
2070 ao2_unlink(q->members, m);
2075 ao2_iterator_destroy(&mem_iter);
2082 static struct call_queue *load_realtime_queue(const char *queuename)
2084 struct ast_variable *queue_vars;
2085 struct ast_config *member_config = NULL;
2086 struct call_queue *q = NULL, tmpq = {
2089 int prev_weight = 0;
2091 /* Find the queue in the in-core list first. */
2092 q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Look for queue in memory first");
2094 if (!q || q->realtime) {
2095 /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all
2096 queue operations while waiting for the DB.
2098 This will be two separate database transactions, so we might
2099 see queue parameters as they were before another process
2100 changed the queue and member list as it was after the change.
2101 Thus we might see an empty member list when a queue is
2102 deleted. In practise, this is unlikely to cause a problem. */
2104 queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL);
2106 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL);
2107 if (!member_config) {
2108 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
2109 ast_variables_destroy(queue_vars);
2114 prev_weight = q->weight ? 1 : 0;
2119 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
2120 if (member_config) {
2121 ast_config_destroy(member_config);
2124 ast_variables_destroy(queue_vars);
2126 /* update the use_weight value if the queue's has gained or lost a weight */
2128 if (!q->weight && prev_weight) {
2129 ast_atomic_fetchadd_int(&use_weight, -1);
2131 if (q->weight && !prev_weight) {
2132 ast_atomic_fetchadd_int(&use_weight, +1);
2135 /* Other cases will end up with the proper value for use_weight */
2139 update_realtime_members(q);
2144 static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
2148 if (ast_strlen_zero(mem->rt_uniqueid))
2151 if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) > 0)
2158 static void update_realtime_members(struct call_queue *q)
2160 struct ast_config *member_config = NULL;
2162 char *interface = NULL;
2163 struct ao2_iterator mem_iter;
2165 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , SENTINEL))) {
2166 /*This queue doesn't have realtime members*/
2167 ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name);
2174 /* Temporarily set realtime members dead so we can detect deleted ones.*/
2175 mem_iter = ao2_iterator_init(q->members, 0);
2176 while ((m = ao2_iterator_next(&mem_iter))) {
2181 ao2_iterator_destroy(&mem_iter);
2183 while ((interface = ast_category_browse(member_config, interface))) {
2184 rt_handle_member_record(q, interface,
2185 ast_variable_retrieve(member_config, interface, "uniqueid"),
2186 S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
2187 ast_variable_retrieve(member_config, interface, "penalty"),
2188 ast_variable_retrieve(member_config, interface, "paused"),
2189 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface));
2192 /* Delete all realtime members that have been deleted in DB. */
2193 mem_iter = ao2_iterator_init(q->members, 0);
2194 while ((m = ao2_iterator_next(&mem_iter))) {
2196 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
2197 ao2_unlink(q->members, m);
2202 ao2_iterator_destroy(&mem_iter);
2205 ast_config_destroy(member_config);
2208 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
2210 struct call_queue *q;
2211 struct queue_ent *cur, *prev = NULL;
2216 if (!(q = load_realtime_queue(queuename)))
2222 /* This is our one */
2225 if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, q->joinempty))) {
2226 *reason = QUEUE_JOINEMPTY;
2232 if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen))
2233 *reason = QUEUE_FULL;
2234 else if (*reason == QUEUE_UNKNOWN) {
2235 /* There's space for us, put us at the right position inside
2237 * Take into account the priority of the calling user */
2242 /* We have higher priority than the current user, enter
2243 * before him, after all the other users with priority
2244 * higher or equal to our priority. */
2245 if ((!inserted) && (qe->prio > cur->prio)) {
2246 insert_entry(q, prev, qe, &pos);
2249 /* <= is necessary for the position comparison because it may not be possible to enter
2250 * at our desired position since higher-priority callers may have taken the position we want
2252 if (!inserted && (qe->prio <= cur->prio) && position && (position <= pos + 1)) {
2253 insert_entry(q, prev, qe, &pos);
2254 /*pos is incremented inside insert_entry, so don't need to add 1 here*/
2255 if (position < pos) {
2256 ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos);
2264 /* No luck, join at the end of the queue */
2266 insert_entry(q, prev, qe, &pos);
2267 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
2268 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
2269 ast_copy_string(qe->context, q->context, sizeof(qe->context));
2272 ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Join",
2273 "Channel: %s\r\nCallerIDNum: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
2275 S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */
2276 S_OR(qe->chan->cid.cid_name, "unknown"),
2277 q->name, qe->pos, q->count, qe->chan->uniqueid );
2278 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
2286 static int play_file(struct ast_channel *chan, const char *filename)
2290 if (ast_strlen_zero(filename)) {
2294 ast_stopstream(chan);
2296 res = ast_streamfile(chan, filename, chan->language);
2298 res = ast_waitstream(chan, AST_DIGIT_ANY);
2300 ast_stopstream(chan);
2306 * \brief Check for valid exit from queue via goto
2307 * \retval 0 if failure
2308 * \retval 1 if successful
2310 static int valid_exit(struct queue_ent *qe, char digit)
2312 int digitlen = strlen(qe->digits);
2314 /* Prevent possible buffer overflow */
2315 if (digitlen < sizeof(qe->digits) - 2) {
2316 qe->digits[digitlen] = digit;
2317 qe->digits[digitlen + 1] = '\0';
2319 qe->digits[0] = '\0';
2323 /* If there's no context to goto, short-circuit */
2324 if (ast_strlen_zero(qe->context))
2327 /* If the extension is bad, then reset the digits to blank */
2328 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) {
2329 qe->digits[0] = '\0';
2333 /* We have an exact match */
2334 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
2335 qe->valid_digits = 1;
2336 /* Return 1 on a successful goto */
2343 static int say_position(struct queue_ent *qe, int ringing)
2345 int res = 0, avgholdmins, avgholdsecs, announceposition = 0;
2349 /* Let minannouncefrequency seconds pass between the start of each position announcement */
2351 if ((now - qe->last_pos) < qe->parent->minannouncefrequency)
2354 /* If either our position has changed, or we are over the freq timer, say position */
2355 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency))
2359 ast_indicate(qe->chan,-1);
2361 ast_moh_stop(qe->chan);
2364 if (qe->parent->announceposition == ANNOUNCEPOSITION_YES ||
2365 qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN ||
2366 (qe->parent->announceposition == ANNOUNCEPOSITION_LIMIT &&
2367 qe->pos <= qe->parent->announcepositionlimit))
2368 announceposition = 1;
2371 if (announceposition == 1) {
2372 /* Say we're next, if we are */
2374 res = play_file(qe->chan, qe->parent->sound_next);
2380 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){
2382 res = play_file(qe->chan, qe->parent->queue_quantity1);
2385 res = ast_say_number(qe->chan, qe->parent->announcepositionlimit, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */
2390 res = play_file(qe->chan, qe->parent->sound_thereare);
2393 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */
2397 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){
2399 res = play_file(qe->chan, qe->parent->queue_quantity2);
2403 res = play_file(qe->chan, qe->parent->sound_calls);
2409 /* Round hold time to nearest minute */
2410 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
2412 /* If they have specified a rounding then round the seconds as well */
2413 if (qe->parent->roundingseconds) {
2414 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
2415 avgholdsecs *= qe->parent->roundingseconds;
2420 ast_verb(3, "Hold time for %s is %d minute(s) %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
2422 /* If the hold time is >1 min, if it's enabled, and if it's not
2423 supposed to be only once and we have already said it, say it */
2424 if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime &&
2425 ((qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE && !qe->last_pos) ||
2426 !(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE))) {
2427 res = play_file(qe->chan, qe->parent->sound_holdtime);
2431 if (avgholdmins >= 1) {
2432 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL);
2436 if (avgholdmins == 1) {
2437 res = play_file(qe->chan, qe->parent->sound_minute);
2441 res = play_file(qe->chan, qe->parent->sound_minutes);
2446 if (avgholdsecs >= 1) {
2447 res = ast_say_number(qe->chan, avgholdmins > 1 ? avgholdsecs : avgholdmins * 60 + avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL);
2451 res = play_file(qe->chan, qe->parent->sound_seconds);
2455 } else if (qe->parent->announceholdtime && !qe->parent->announceposition) {
2460 if (qe->parent->announceposition) {
2461 ast_verb(3, "Told %s in %s their queue position (which was %d)\n",
2462 qe->chan->name, qe->parent->name, qe->pos);
2465 res = play_file(qe->chan, qe->parent->sound_thanks);
2469 if ((res > 0 && !valid_exit(qe, res)))
2472 /* Set our last_pos indicators */
2474 qe->last_pos_said = qe->pos;
2476 /* Don't restart music on hold if we're about to exit the caller from the queue */
2479 ast_indicate(qe->chan, AST_CONTROL_RINGING);
2481 ast_moh_start(qe->chan, qe->moh, NULL);
2487 static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
2491 /* Calculate holdtime using an exponential average */
2492 /* Thanks to SRT for this contribution */
2493 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
2495 ao2_lock(qe->parent);
2496 oldvalue = qe->parent->holdtime;
2497 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
2498 ao2_unlock(qe->parent);
2501 /*! \brief Caller leaving queue.
2503 * Search the queue to find the leaving client, if found remove from queue
2504 * create manager event, move others up the queue.
2506 static void leave_queue(struct queue_ent *qe)
2508 struct call_queue *q;
2509 struct queue_ent *current, *prev = NULL;
2510 struct penalty_rule *pr_iter;
2513 if (!(q = qe->parent))
2515 queue_t_ref(q, "Copy queue pointer from queue entry");
2519 for (current = q->head; current; current = current->next) {
2520 if (current == qe) {
2524 /* Take us out of the queue */
2525 ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Leave",
2526 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nPosition: %d\r\nUniqueid: %s\r\n",
2527 qe->chan->name, q->name, q->count, qe->pos, qe->chan->uniqueid);
2528 ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
2529 /* Take us out of the queue */
2531 prev->next = current->next;
2533 q->head = current->next;
2534 /* Free penalty rules */
2535 while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list)))
2537 snprintf(posstr, sizeof(posstr), "%d", qe->pos);
2538 pbx_builtin_setvar_helper(qe->chan, "QUEUEPOSITION", posstr);
2540 /* Renumber the people after us in the queue based on a new count */
2541 current->pos = ++pos;
2547 /*If the queue is a realtime queue, check to see if it's still defined in real time*/
2549 struct ast_variable *var;
2550 if (!(var = ast_load_realtime("queues", "name", q->name, SENTINEL))) {
2553 ast_variables_destroy(var);
2558 /* It's dead and nobody is in it, so kill it */
2559 queues_t_unlink(queues, q, "Queue is now dead; remove it from the container");
2561 /* unref the explicit ref earlier in the function */
2562 queue_t_unref(q, "Expire copied reference");
2565 /*! \brief Hang up a list of outgoing calls */
2566 static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere)
2568 struct callattempt *oo;
2571 /* If someone else answered the call we should indicate this in the CANCEL */
2572 /* Hangup any existing lines we have open */
2573 if (outgoing->chan && (outgoing->chan != exception || cancel_answered_elsewhere)) {
2574 if (exception || cancel_answered_elsewhere)
2575 ast_set_flag(outgoing->chan, AST_FLAG_ANSWERED_ELSEWHERE);
2576 ast_hangup(outgoing->chan);
2579 outgoing = outgoing->q_next;
2581 ao2_ref(oo->member, -1);
2587 * \brief Get the number of members available to accept a call.
2589 * \note The queue passed in should be locked prior to this function call
2591 * \param[in] q The queue for which we are couting the number of available members
2592 * \return Return the number of available members in queue q
2594 static int num_available_members(struct call_queue *q)
2598 struct ao2_iterator mem_iter;
2600 mem_iter = ao2_iterator_init(q->members, 0);
2601 while ((mem = ao2_iterator_next(&mem_iter))) {
2602 switch (mem->status) {
2603 case AST_DEVICE_INUSE:
2606 /* else fall through */
2607 case AST_DEVICE_NOT_INUSE:
2608 case AST_DEVICE_UNKNOWN:
2616 /* If autofill is not enabled or if the queue's strategy is ringall, then
2617 * we really don't care about the number of available members so much as we
2618 * do that there is at least one available.
2620 * In fact, we purposely will return from this function stating that only
2621 * one member is available if either of those conditions hold. That way,
2622 * functions which determine what action to take based on the number of available
2623 * members will operate properly. The reasoning is that even if multiple
2624 * members are available, only the head caller can actually be serviced.
2626 if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) {
2630 ao2_iterator_destroy(&mem_iter);
2635 /* traverse all defined queues which have calls waiting and contain this member
2636 return 0 if no other queue has precedence (higher weight) or 1 if found */
2637 static int compare_weight(struct call_queue *rq, struct member *member)
2639 struct call_queue *q;
2642 struct ao2_iterator queue_iter;
2644 /* q's lock and rq's lock already set by try_calling()
2645 * to solve deadlock */
2646 queue_iter = ao2_iterator_init(queues, 0);
2647 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
2648 if (q == rq) { /* don't check myself, could deadlock */
2649 queue_t_unref(q, "Done with iterator");
2653 if (q->count && q->members) {
2654 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
2655 ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
2656 if (q->weight > rq->weight && q->count >= num_available_members(q)) {
2657 ast_debug(1, "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);
2664 queue_t_unref(q, "Done with iterator");
2669 ao2_iterator_destroy(&queue_iter);
2673 /*! \brief common hangup actions */
2674 static void do_hang(struct callattempt *o)
2677 ast_hangup(o->chan);
2681 /*! \brief convert "\n" to "\nVariable: " ready for manager to use */
2682 static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
2684 struct ast_str *buf = ast_str_thread_get(&ast_str_thread_global_buf, len + 1);
2687 if (pbx_builtin_serialize_variables(chan, &buf)) {
2690 /* convert "\n" to "\nVariable: " */
2691 strcpy(vars, "Variable: ");
2692 tmp = ast_str_buffer(buf);
2694 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) {
2697 if (tmp[i + 1] == '\0')
2699 if (tmp[i] == '\n') {
2703 ast_copy_string(&(vars[j]), "Variable: ", len - j);
2713 /* there are no channel variables; leave it blank */
2720 * \brief Part 2 of ring_one
2722 * Does error checking before attempting to request a channel and call a member.
2723 * This function is only called from ring_one().
2724 * Failure can occur if:
2727 * - Wrapup time not expired
2728 * - Priority by another queue
2730 * \retval 1 on success to reach a free agent
2731 * \retval 0 on failure to get agent.
2733 static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
2739 const char *macrocontext, *macroexten;
2741 /* on entry here, we know that tmp->chan == NULL */
2742 if ((tmp->lastqueue && tmp->lastqueue->wrapuptime && (time(NULL) - tmp->lastcall < tmp->lastqueue->wrapuptime)) ||
2743 (!tmp->lastqueue && qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime))) {
2744 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
2745 (tmp->lastqueue ? tmp->lastqueue->name : qe->parent->name), tmp->interface);
2747 ast_cdr_busy(qe->chan->cdr);
2748 tmp->stillgoing = 0;
2753 if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
2754 ast_debug(1, "%s in use, can't receive call\n", tmp->interface);
2756 ast_cdr_busy(qe->chan->cdr);
2757 tmp->stillgoing = 0;
2761 if (tmp->member->paused) {
2762 ast_debug(1, "%s paused, can't receive call\n", tmp->interface);
2764 ast_cdr_busy(qe->chan->cdr);
2765 tmp->stillgoing = 0;
2768 if (use_weight && compare_weight(qe->parent,tmp->member)) {
2769 ast_debug(1, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
2771 ast_cdr_busy(qe->chan->cdr);
2772 tmp->stillgoing = 0;
2777 ast_copy_string(tech, tmp->interface, sizeof(tech));
2778 if ((location = strchr(tech, '/')))
2783 /* Request the peer */
2784 tmp->chan = ast_request(tech, qe->chan->nativeformats, qe->chan, location, &status);
2785 if (!tmp->chan) { /* If we can't, just go on to the next call */
2787 ast_cdr_busy(qe->chan->cdr);
2788 tmp->stillgoing = 0;
2790 ao2_lock(qe->parent);
2791 update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member));
2792 qe->parent->rrpos++;
2794 ao2_unlock(qe->parent);
2800 ast_channel_lock(tmp->chan);
2801 while (ast_channel_trylock(qe->chan)) {
2802 CHANNEL_DEADLOCK_AVOIDANCE(tmp->chan);
2805 if (qe->cancel_answered_elsewhere) {
2806 ast_set_flag(tmp->chan, AST_FLAG_ANSWERED_ELSEWHERE);
2808 tmp->chan->appl = "AppQueue";
2809 tmp->chan->data = "(Outgoing Line)";
2810 memset(&tmp->chan->whentohangup, 0, sizeof(tmp->chan->whentohangup));
2812 /* If the new channel has no callerid, try to guess what it should be */
2813 if (ast_strlen_zero(tmp->chan->cid.cid_num)) {
2814 if (!ast_strlen_zero(qe->chan->connected.id.number)) {
2815 ast_set_callerid(tmp->chan, qe->chan->connected.id.number, qe->chan->connected.id.name, qe->chan->connected.ani);
2816 tmp->chan->cid.cid_pres = qe->chan->connected.id.number_presentation;
2817 } else if (!ast_strlen_zero(qe->chan->cid.cid_dnid)) {
2818 ast_set_callerid(tmp->chan, qe->chan->cid.cid_dnid, NULL, NULL);
2819 } else if (!ast_strlen_zero(S_OR(qe->chan->macroexten, qe->chan->exten))) {
2820 ast_set_callerid(tmp->chan, S_OR(qe->chan->macroexten, qe->chan->exten), NULL, NULL);
2822 tmp->update_connectedline = 0;
2825 if (tmp->chan->cid.cid_rdnis)
2826 ast_free(tmp->chan->cid.cid_rdnis);
2827 tmp->chan->cid.cid_rdnis = ast_strdup(qe->chan->cid.cid_rdnis);
2828 ast_party_redirecting_copy(&tmp->chan->redirecting, &qe->chan->redirecting);
2830 tmp->chan->cid.cid_tns = qe->chan->cid.cid_tns;
2832 ast_connected_line_copy_from_caller(&tmp->chan->connected, &qe->chan->cid);
2834 /* Inherit specially named variables from parent channel */
2835 ast_channel_inherit_variables(qe->chan, tmp->chan);
2836 ast_channel_datastore_inherit(qe->chan, tmp->chan);
2838 /* Presense of ADSI CPE on outgoing channel follows ours */
2839 tmp->chan->adsicpe = qe->chan->adsicpe;
2841 /* Inherit context and extension */
2842 macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT");
2843 ast_string_field_set(tmp->chan, dialcontext, ast_strlen_zero(macrocontext) ? qe->chan->context : macrocontext);
2844 macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN");
2845 if (!ast_strlen_zero(macroexten))
2846 ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten));
2848 ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten));
2849 if (ast_cdr_isset_unanswered()) {
2850 /* they want to see the unanswered dial attempts! */
2851 /* set up the CDR fields on all the CDRs to give sensical information */
2852 ast_cdr_setdestchan(tmp->chan->cdr, tmp->chan->name);
2853 strcpy(tmp->chan->cdr->clid, qe->chan->cdr->clid);
2854 strcpy(tmp->chan->cdr->channel, qe->chan->cdr->channel);
2855 strcpy(tmp->chan->cdr->src, qe->chan->cdr->src);
2856 strcpy(tmp->chan->cdr->dst, qe->chan->exten);
2857 strcpy(tmp->chan->cdr->dcontext, qe->chan->context);
2858 strcpy(tmp->chan->cdr->lastapp, qe->chan->cdr->lastapp);
2859 strcpy(tmp->chan->cdr->lastdata, qe->chan->cdr->lastdata);
2860 tmp->chan->cdr->amaflags = qe->chan->cdr->amaflags;
2861 strcpy(tmp->chan->cdr->accountcode, qe->chan->cdr->accountcode);
2862 strcpy(tmp->chan->cdr->userfield, qe->chan->cdr->userfield);
2865 /* Place the call, but don't wait on the answer */
2866 if ((res = ast_call(tmp->chan, location, 0))) {
2867 /* Again, keep going even if there's an error */
2868 ast_debug(1, "ast call on peer returned %d\n", res);
2869 ast_verb(3, "Couldn't call %s\n", tmp->interface);
2870 ast_channel_unlock(tmp->chan);
2871 ast_channel_unlock(qe->chan);
2874 update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member));
2876 } else if (qe->parent->eventwhencalled) {
2879 manager_event(EVENT_FLAG_AGENT, "AgentCalled",
2881 "AgentCalled: %s\r\n"
2883 "ChannelCalling: %s\r\n"
2884 "DestinationChannel: %s\r\n"
2885 "CallerIDNum: %s\r\n"
2886 "CallerIDName: %s\r\n"
2892 qe->parent->name, tmp->interface, tmp->member->membername, qe->chan->name, tmp->chan->name,
2893 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
2894 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
2895 qe->chan->context, qe->chan->exten, qe->chan->priority, qe->chan->uniqueid,
2896 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
2897 ast_verb(3, "Called %s\n", tmp->interface);
2899 ast_channel_unlock(tmp->chan);
2900 ast_channel_unlock(qe->chan);
2902 update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member));
2906 /*! \brief find the entry with the best metric, or NULL */
2907 static struct callattempt *find_best(struct callattempt *outgoing)
2909 struct callattempt *best = NULL, *cur;
2911 for (cur = outgoing; cur; cur = cur->q_next) {
2912 if (cur->stillgoing && /* Not already done */
2913 !cur->chan && /* Isn't already going */
2914 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */
2923 * \brief Place a call to a queue member.
2925 * Once metrics have been calculated for each member, this function is used
2926 * to place a call to the appropriate member (or members). The low-level
2927 * channel-handling and error detection is handled in ring_entry
2929 * \retval 1 if a member was called successfully
2930 * \retval 0 otherwise
2932 static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
2937 struct callattempt *best = find_best(outgoing);
2939 ast_debug(1, "Nobody left to try ringing in queue\n");
2942 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
2943 struct callattempt *cur;
2944 /* Ring everyone who shares this best metric (for ringall) */
2945 for (cur = outgoing; cur; cur = cur->q_next) {