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>Ring instead of playing MOH when a member channel is actually ringing.</para>
160 <para>Allow the <emphasis>called</emphasis> user to transfer the calling user.</para>
163 <para>Allow the <emphasis>calling</emphasis> user to transfer the call.</para>
166 <para>Allow the <emphasis>called</emphasis> user to write the conversation to
167 disk via Monitor.</para>
170 <para>Allow the <emphasis>calling</emphasis> user to write the conversation to
171 disk via Monitor.</para>
174 <para>Allow the <emphasis>called</emphasis> party to enable parking of the call by sending
175 the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
178 <para>Allow the <emphasis>calling</emphasis> party to enable parking of the call by sending
179 the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
182 <para>Allow the <emphasis>called</emphasis> user to write the conversation
183 to disk via MixMonitor.</para>
186 <para>Allow the <emphasis>calling</emphasis> user to write the conversation to
187 disk via MixMonitor.</para>
191 <parameter name="URL">
192 <para><replaceable>URL</replaceable> will be sent to the called party if the channel supports it.</para>
194 <parameter name="announceoverride" />
195 <parameter name="timeout">
196 <para>Will cause the queue to fail out after a specified number of
197 seconds, checked between each <filename>queues.conf</filename> <replaceable>timeout</replaceable> and
198 <replaceable>retry</replaceable> cycle.</para>
200 <parameter name="AGI">
201 <para>Will setup an AGI script to be executed on the calling party's channel once they are
202 connected to a queue member.</para>
204 <parameter name="macro">
205 <para>Will run a macro on the calling party's channel once they are connected to a queue member.</para>
207 <parameter name="gosub">
208 <para>Will run a gosub on the calling party's channel once they are connected to a queue member.</para>
210 <parameter name="rule">
211 <para>Will cause the queue's defaultrule to be overridden by the rule specified.</para>
213 <parameter name="position">
214 <para>Attempt to enter the caller into the queue at the numerical position specified. <literal>1</literal>
215 would attempt to enter the caller at the head of the queue, and <literal>3</literal> would attempt to place
216 the caller third in the queue.</para>
220 <para>In addition to transferring the call, a call may be parked and then picked
221 up by another user.</para>
222 <para>This application will return to the dialplan if the queue does not exist, or
223 any of the join options cause the caller to not enter the queue.</para>
224 <para>This application sets the following channel variable upon completion:</para>
226 <variable name="QUEUESTATUS">
227 <para>The status of the call as a text string.</para>
228 <value name="TIMEOUT" />
229 <value name="FULL" />
230 <value name="JOINEMPTY" />
231 <value name="LEAVEEMPTY" />
232 <value name="JOINUNAVAIL" />
233 <value name="LEAVEUNAVAIL" />
234 <value name="CONTINUE" />
239 <ref type="application">AddQueueMember</ref>
240 <ref type="application">RemoveQueueMember</ref>
241 <ref type="application">PauseQueueMember</ref>
242 <ref type="application">UnpauseQueueMember</ref>
243 <ref type="application">AgentLogin</ref>
244 <ref type="function">QUEUE_MEMBER_COUNT</ref>
245 <ref type="function">QUEUE_MEMBER_LIST</ref>
246 <ref type="function">QUEUE_WAITING_COUNT</ref>
249 <application name="AddQueueMember" language="en_US">
251 Dynamically adds queue members.
254 <parameter name="queuename" required="true" />
255 <parameter name="interface" />
256 <parameter name="penalty" />
257 <parameter name="options" />
258 <parameter name="membername" />
259 <parameter name="stateinterface" />
262 <para>Dynamically adds interface to an existing queue. If the interface is
263 already in the queue it will return an error.</para>
264 <para>This application sets the following channel variable upon completion:</para>
266 <variable name="AQMSTATUS">
267 <para>The status of the attempt to add a queue member as a text string.</para>
268 <value name="ADDED" />
269 <value name="MEMBERALREADY" />
270 <value name="NOSUCHQUEUE" />
275 <ref type="application">RemoveQueueMember</ref>
276 <ref type="application">PauseQueueMember</ref>
277 <ref type="application">UnpauseQueueMember</ref>
278 <ref type="application">AgentLogin</ref>
281 <application name="RemoveQueueMember" language="en_US">
283 Dynamically removes queue members.
286 <parameter name="queuename" required="true" />
287 <parameter name="interface" />
288 <parameter name="options" />
291 <para>If the interface is <emphasis>NOT</emphasis> in the queue it will return an error.</para>
292 <para>This application sets the following channel variable upon completion:</para>
294 <variable name="RQMSTATUS">
295 <value name="REMOVED" />
296 <value name="NOTINQUEUE" />
297 <value name="NOSUCHQUEUE" />
300 <para>Example: RemoveQueueMember(techsupport,SIP/3000)</para>
303 <ref type="application">Queue</ref>
304 <ref type="application">AddQueueMember</ref>
305 <ref type="application">PauseQueueMember</ref>
306 <ref type="application">UnpauseQueueMember</ref>
309 <application name="PauseQueueMember" language="en_US">
311 Pauses a queue member.
314 <parameter name="queuename" />
315 <parameter name="interface" required="true" />
316 <parameter name="options" />
317 <parameter name="reason">
318 <para>Is used to add extra information to the appropriate queue_log entries and manager events.</para>
322 <para>Pauses (blocks calls for) a queue member. The given interface will be paused in the given queue.
323 This prevents any calls from being sent from the queue to the interface until it is
324 unpaused with UnpauseQueueMember or the manager interface. If no queuename is given,
325 the interface is paused in every queue it is a member of. The application will fail if the
326 interface is not found.</para>
327 <para>This application sets the following channel variable upon completion:</para>
329 <variable name="PQMSTATUS">
330 <para>The status of the attempt to pause a queue member as a text string.</para>
331 <value name="PAUSED" />
332 <value name="NOTFOUND" />
335 <para>Example: PauseQueueMember(,SIP/3000)</para>
338 <ref type="application">UnpauseQueueMember</ref>
341 <application name="UnpauseQueueMember" language="en_US">
343 Unpauses a queue member.
346 <parameter name="queuename" />
347 <parameter name="interface" required="true" />
348 <parameter name="options" />
349 <parameter name="reason">
350 <para>Is used to add extra information to the appropriate queue_log entries and manager events.</para>
354 <para>Unpauses (resumes calls to) a queue member. This is the counterpart to <literal>PauseQueueMember()</literal>
355 and operates exactly the same way, except it unpauses instead of pausing the given interface.</para>
356 <para>This application sets the following channel variable upon completion:</para>
358 <variable name="UPQMSTATUS">
359 <para>The status of the attempt to unpause a queue member as a text string.</para>
360 <value name="UNPAUSED" />
361 <value name="NOTFOUND" />
364 <para>Example: UnpauseQueueMember(,SIP/3000)</para>
367 <ref type="application">PauseQueueMember</ref>
370 <application name="QueueLog" language="en_US">
372 Writes to the queue_log file.
375 <parameter name="queuename" required="true" />
376 <parameter name="uniqueid" required="true" />
377 <parameter name="agent" required="true" />
378 <parameter name="event" required="true" />
379 <parameter name="additionalinfo" />
382 <para>Allows you to write your own events into the queue log.</para>
383 <para>Example: QueueLog(101,${UNIQUEID},${AGENT},WENTONBREAK,600)</para>
386 <ref type="application">Queue</ref>
389 <function name="QUEUE_VARIABLES" language="en_US">
391 Return Queue information in variables.
394 <parameter name="queuename" required="true">
396 <enum name="QUEUEMAX">
397 <para>Maxmimum number of calls allowed.</para>
399 <enum name="QUEUESTRATEGY">
400 <para>The strategy of the queue.</para>
402 <enum name="QUEUECALLS">
403 <para>Number of calls currently in the queue.</para>
405 <enum name="QUEUEHOLDTIME">
406 <para>Current average hold time.</para>
408 <enum name="QUEUECOMPLETED">
409 <para>Number of completed calls for the queue.</para>
411 <enum name="QUEUEABANDONED">
412 <para>Number of abandoned calls.</para>
414 <enum name="QUEUESRVLEVEL">
415 <para>Queue service level.</para>
417 <enum name="QUEUESRVLEVELPERF">
418 <para>Current service level performance.</para>
424 <para>Makes the following queue variables available.</para>
425 <para>Returns <literal>0</literal> if queue is found and setqueuevar is defined, <literal>-1</literal> otherwise.</para>
428 <function name="QUEUE_MEMBER" language="en_US">
430 Count number of members answering a queue.
433 <parameter name="queuename" required="true" />
434 <parameter name="option" required="true">
437 <para>Returns the number of logged-in members for the specified queue.</para>
440 <para>Returns the number of logged-in members for the specified queue available to take a call.</para>
443 <para>Returns the total number of members for the specified queue.</para>
449 <para>Returns the number of members currently associated with the specified <replaceable>queuename</replaceable>.</para>
452 <function name="QUEUE_MEMBER_COUNT" language="en_US">
454 Count number of members answering a queue.
457 <parameter name="queuename" required="true" />
460 <para>Returns the number of members currently associated with the specified <replaceable>queuename</replaceable>.</para>
461 <warning><para>This function has been deprecated in favor of the <literal>QUEUE_MEMBER()</literal> function</para></warning>
464 <ref type="function">QUEUE_MEMBER_LIST</ref>
467 <function name="QUEUE_WAITING_COUNT" language="en_US">
469 Count number of calls currently waiting in a queue.
472 <parameter name="queuename" />
475 <para>Returns the number of callers currently waiting in the specified <replaceable>queuename</replaceable>.</para>
478 <function name="QUEUE_MEMBER_LIST" language="en_US">
480 Returns a list of interfaces on a queue.
483 <parameter name="queuename" required="true" />
486 <para>Returns a comma-separated list of members associated with the specified <replaceable>queuename</replaceable>.</para>
489 <ref type="function">QUEUE_MEMBER_COUNT</ref>
492 <function name="QUEUE_MEMBER_PENALTY" language="en_US">
494 Gets or sets queue members penalty.
497 <parameter name="queuename" required="true" />
498 <parameter name="interface" required="true" />
501 <para>Gets or sets queue members penalty.</para>
504 <manager name="Queues" language="en_US">
509 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
514 <manager name="QueueStatus" language="en_US">
519 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
520 <parameter name="Queue" />
521 <parameter name="Member" />
526 <manager name="QueueSummary" language="en_US">
531 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
532 <parameter name="Queue" />
537 <manager name="QueueAdd" language="en_US">
539 Add interface to queue.
542 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
543 <parameter name="Queue" required="true" />
544 <parameter name="Interface" required="true" />
545 <parameter name="Penalty" />
546 <parameter name="Paused" />
547 <parameter name="MemberName" />
548 <parameter name="StateInterface" />
553 <manager name="QueueRemove" language="en_US">
555 Remove interface from queue.
558 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
559 <parameter name="Queue" required="true" />
560 <parameter name="Interface" required="true" />
565 <manager name="QueuePause" language="en_US">
567 Makes a queue member temporarily unavailable.
570 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
571 <parameter name="Interface" required="true" />
572 <parameter name="Paused" required="true" />
573 <parameter name="Queue" />
574 <parameter name="Reason" />
579 <manager name="QueueLog" language="en_US">
581 Adds custom entry in queue_log.
584 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
585 <parameter name="Queue" required="true" />
586 <parameter name="Event" required="true" />
587 <parameter name="Uniqueid" />
588 <parameter name="Interface" />
589 <parameter name="Message" />
594 <manager name="QueuePenalty" language="en_US">
596 Set the penalty for a queue member.
599 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
600 <parameter name="Interface" required="true" />
601 <parameter name="Penalty" required="true" />
602 <parameter name="Queue" />
607 <manager name="QueueRule" language="en_US">
612 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
613 <parameter name="Rule" />
618 <manager name="QueueReload" language="en_US">
620 Reload a queue, queues, or any sub-section of a queue or queues.
623 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
624 <parameter name="Queue" />
625 <parameter name="Members">
631 <parameter name="Rules">
637 <parameter name="Parameters">
647 <manager name="QueueReset" language="en_US">
649 Reset queue statistics.
652 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
653 <parameter name="Queue" />
661 QUEUE_STRATEGY_RINGALL = 0,
662 QUEUE_STRATEGY_LEASTRECENT,
663 QUEUE_STRATEGY_FEWESTCALLS,
664 QUEUE_STRATEGY_RANDOM,
665 QUEUE_STRATEGY_RRMEMORY,
666 QUEUE_STRATEGY_LINEAR,
667 QUEUE_STRATEGY_WRANDOM
670 enum queue_reload_mask {
671 QUEUE_RELOAD_PARAMETERS = (1 << 0),
672 QUEUE_RELOAD_MEMBER = (1 << 1),
673 QUEUE_RELOAD_RULES = (1 << 2),
674 QUEUE_RESET_STATS = (1 << 3),
677 static const struct strategy {
681 { QUEUE_STRATEGY_RINGALL, "ringall" },
682 { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
683 { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
684 { QUEUE_STRATEGY_RANDOM, "random" },
685 { QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
686 { QUEUE_STRATEGY_RRMEMORY, "roundrobin" },
687 { QUEUE_STRATEGY_LINEAR, "linear" },
688 { QUEUE_STRATEGY_WRANDOM, "wrandom"},
691 static struct ast_taskprocessor *devicestate_tps;
693 #define DEFAULT_RETRY 5
694 #define DEFAULT_TIMEOUT 15
695 #define RECHECK 1 /*!< Recheck every second to see we we're at the top yet */
696 #define MAX_PERIODIC_ANNOUNCEMENTS 10 /*!< The maximum periodic announcements we can have */
697 #define DEFAULT_MIN_ANNOUNCE_FREQUENCY 15 /*!< The minimum number of seconds between position announcements \
698 The default value of 15 provides backwards compatibility */
699 #define MAX_QUEUE_BUCKETS 53
701 #define RES_OKAY 0 /*!< Action completed */
702 #define RES_EXISTS (-1) /*!< Entry already exists */
703 #define RES_OUTOFMEMORY (-2) /*!< Out of memory */
704 #define RES_NOSUCHQUEUE (-3) /*!< No such queue */
705 #define RES_NOT_DYNAMIC (-4) /*!< Member is not dynamic */
707 static char *app = "Queue";
709 static char *app_aqm = "AddQueueMember" ;
711 static char *app_rqm = "RemoveQueueMember" ;
713 static char *app_pqm = "PauseQueueMember" ;
715 static char *app_upqm = "UnpauseQueueMember" ;
717 static char *app_ql = "QueueLog" ;
719 /*! \brief Persistent Members astdb family */
720 static const char * const pm_family = "Queue/PersistentMembers";
721 /* The maximum length of each persistent member queue database entry */
722 #define PM_MAX_LEN 8192
724 /*! \brief queues.conf [general] option */
725 static int queue_persistent_members = 0;
727 /*! \brief queues.conf per-queue weight option */
728 static int use_weight = 0;
730 /*! \brief queues.conf [general] option */
731 static int autofill_default = 0;
733 /*! \brief queues.conf [general] option */
734 static int montype_default = 0;
736 /*! \brief queues.conf [general] option */
737 static int shared_lastcall = 0;
739 /*! \brief Subscription to device state change events */
740 static struct ast_event_sub *device_state_sub;
742 /*! \brief queues.conf [general] option */
743 static int update_cdr = 0;
749 QUEUE_LEAVEEMPTY = 3,
750 QUEUE_JOINUNAVAIL = 4,
751 QUEUE_LEAVEUNAVAIL = 5,
756 static const struct {
757 enum queue_result id;
759 } queue_results[] = {
760 { QUEUE_UNKNOWN, "UNKNOWN" },
761 { QUEUE_TIMEOUT, "TIMEOUT" },
762 { QUEUE_JOINEMPTY,"JOINEMPTY" },
763 { QUEUE_LEAVEEMPTY, "LEAVEEMPTY" },
764 { QUEUE_JOINUNAVAIL, "JOINUNAVAIL" },
765 { QUEUE_LEAVEUNAVAIL, "LEAVEUNAVAIL" },
766 { QUEUE_FULL, "FULL" },
767 { QUEUE_CONTINUE, "CONTINUE" },
770 enum queue_timeout_priority {
771 TIMEOUT_PRIORITY_APP,
772 TIMEOUT_PRIORITY_CONF,
775 /*! \brief We define a custom "local user" structure because we
776 * use it not only for keeping track of what is in use but
777 * also for keeping track of who we're dialing.
779 * There are two "links" defined in this structure, q_next and call_next.
780 * q_next links ALL defined callattempt structures into a linked list. call_next is
781 * a link which allows for a subset of the callattempts to be traversed. This subset
782 * is used in wait_for_answer so that irrelevant callattempts are not traversed. This
783 * also is helpful so that queue logs are always accurate in the case where a call to
784 * a member times out, especially if using the ringall strategy.
788 struct callattempt *q_next;
789 struct callattempt *call_next;
790 struct ast_channel *chan;
796 struct call_queue *lastqueue;
797 struct member *member;
798 unsigned int update_connectedline:1;
799 struct ast_party_connected_line connected;
804 struct call_queue *parent; /*!< What queue is our parent */
805 char moh[80]; /*!< Name of musiconhold to be used */
806 char announce[80]; /*!< Announcement to play for member when call is answered */
807 char context[AST_MAX_CONTEXT]; /*!< Context when user exits queue */
808 char digits[AST_MAX_EXTENSION]; /*!< Digits entered while in queue */
809 int valid_digits; /*!< Digits entered correspond to valid extension. Exited */
810 int pos; /*!< Where we are in the queue */
811 int prio; /*!< Our priority */
812 int last_pos_said; /*!< Last position we told the user */
813 int ring_when_ringing; /*!< Should we only use ring indication when a channel is ringing? */
814 time_t last_periodic_announce_time; /*!< The last time we played a periodic announcement */
815 int last_periodic_announce_sound; /*!< The last periodic announcement we made */
816 time_t last_pos; /*!< Last time we told the user their position */
817 int opos; /*!< Where we started in the queue */
818 int handled; /*!< Whether our call was handled */
819 int pending; /*!< Non-zero if we are attempting to call a member */
820 int max_penalty; /*!< Limit the members that can take this call to this penalty or lower */
821 int min_penalty; /*!< Limit the members that can take this call to this penalty or higher */
822 int linpos; /*!< If using linear strategy, what position are we at? */
823 int linwrapped; /*!< Is the linpos wrapped? */
824 time_t start; /*!< When we started holding */
825 time_t expire; /*!< When this entry should expire (time out of queue) */
826 int cancel_answered_elsewhere; /*!< Whether we should force the CAE flag on this call (C) option*/
827 struct ast_channel *chan; /*!< Our channel */
828 AST_LIST_HEAD_NOLOCK(,penalty_rule) qe_rules; /*!< Local copy of the queue's penalty rules */
829 struct penalty_rule *pr; /*!< Pointer to the next penalty rule to implement */
830 struct queue_ent *next; /*!< The next queue entry */
834 char interface[80]; /*!< Technology/Location to dial to reach this member*/
835 char state_exten[AST_MAX_EXTENSION]; /*!< Extension to get state from (if using hint) */
836 char state_context[AST_MAX_CONTEXT]; /*!< Context to use when getting state (if using hint) */
837 char state_interface[80]; /*!< Technology/Location from which to read devicestate changes */
838 char membername[80]; /*!< Member name to use in queue logs */
839 int penalty; /*!< Are we a last resort? */
840 int calls; /*!< Number of calls serviced by this member */
841 int dynamic; /*!< Are we dynamically added? */
842 int realtime; /*!< Is this member realtime? */
843 int status; /*!< Status of queue member */
844 int paused; /*!< Are we paused (not accepting calls)? */
845 time_t lastcall; /*!< When last successful call was hungup */
846 struct call_queue *lastqueue; /*!< Last queue we received a call */
847 unsigned int dead:1; /*!< Used to detect members deleted in realtime */
848 unsigned int delme:1; /*!< Flag to delete entry on reload */
849 char rt_uniqueid[80]; /*!< Unique id of realtime member entry */
852 enum empty_conditions {
853 QUEUE_EMPTY_PENALTY = (1 << 0),
854 QUEUE_EMPTY_PAUSED = (1 << 1),
855 QUEUE_EMPTY_INUSE = (1 << 2),
856 QUEUE_EMPTY_RINGING = (1 << 3),
857 QUEUE_EMPTY_UNAVAILABLE = (1 << 4),
858 QUEUE_EMPTY_INVALID = (1 << 5),
859 QUEUE_EMPTY_UNKNOWN = (1 << 6),
860 QUEUE_EMPTY_WRAPUP = (1 << 7),
863 /* values used in multi-bit flags in call_queue */
864 #define ANNOUNCEHOLDTIME_ALWAYS 1
865 #define ANNOUNCEHOLDTIME_ONCE 2
866 #define QUEUE_EVENT_VARIABLES 3
868 struct penalty_rule {
869 int time; /*!< Number of seconds that need to pass before applying this rule */
870 int max_value; /*!< The amount specified in the penalty rule for max penalty */
871 int min_value; /*!< The amount specified in the penalty rule for min penalty */
872 int max_relative; /*!< Is the max adjustment relative? 1 for relative, 0 for absolute */
873 int min_relative; /*!< Is the min adjustment relative? 1 for relative, 0 for absolute */
874 AST_LIST_ENTRY(penalty_rule) list; /*!< Next penalty_rule */
877 #define ANNOUNCEPOSITION_YES 1 /*!< We announce position */
878 #define ANNOUNCEPOSITION_NO 2 /*!< We don't announce position */
879 #define ANNOUNCEPOSITION_MORE_THAN 3 /*!< We say "Currently there are more than <limit>" */
880 #define ANNOUNCEPOSITION_LIMIT 4 /*!< We not announce position more than <limit> */
883 AST_DECLARE_STRING_FIELDS(
885 AST_STRING_FIELD(name);
886 /*! Music on Hold class */
887 AST_STRING_FIELD(moh);
888 /*! Announcement to play when call is answered */
889 AST_STRING_FIELD(announce);
891 AST_STRING_FIELD(context);
892 /*! Macro to run upon member connection */
893 AST_STRING_FIELD(membermacro);
894 /*! Gosub to run upon member connection */
895 AST_STRING_FIELD(membergosub);
896 /*! Default rule to use if none specified in call to Queue() */
897 AST_STRING_FIELD(defaultrule);
898 /*! Sound file: "Your call is now first in line" (def. queue-youarenext) */
899 AST_STRING_FIELD(sound_next);
900 /*! Sound file: "There are currently" (def. queue-thereare) */
901 AST_STRING_FIELD(sound_thereare);
902 /*! Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting) */
903 AST_STRING_FIELD(sound_calls);
904 /*! Sound file: "Currently there are more than" (def. queue-quantity1) */
905 AST_STRING_FIELD(queue_quantity1);
906 /*! Sound file: "callers waiting to speak with a representative" (def. queue-quantity2) */
907 AST_STRING_FIELD(queue_quantity2);
908 /*! Sound file: "The current estimated total holdtime is" (def. queue-holdtime) */
909 AST_STRING_FIELD(sound_holdtime);
910 /*! Sound file: "minutes." (def. queue-minutes) */
911 AST_STRING_FIELD(sound_minutes);
912 /*! Sound file: "minute." (def. queue-minute) */
913 AST_STRING_FIELD(sound_minute);
914 /*! Sound file: "seconds." (def. queue-seconds) */
915 AST_STRING_FIELD(sound_seconds);
916 /*! Sound file: "Thank you for your patience." (def. queue-thankyou) */
917 AST_STRING_FIELD(sound_thanks);
918 /*! Sound file: Custom announce for caller, no default */
919 AST_STRING_FIELD(sound_callerannounce);
920 /*! Sound file: "Hold time" (def. queue-reporthold) */
921 AST_STRING_FIELD(sound_reporthold);
923 /*! Sound files: Custom announce, no default */
924 struct ast_str *sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS];
926 unsigned int eventwhencalled:2;
927 unsigned int ringinuse:1;
928 unsigned int setinterfacevar:1;
929 unsigned int setqueuevar:1;
930 unsigned int setqueueentryvar:1;
931 unsigned int reportholdtime:1;
932 unsigned int wrapped:1;
933 unsigned int timeoutrestart:1;
934 unsigned int announceholdtime:2;
935 unsigned int announceposition:3;
937 unsigned int maskmemberstatus:1;
938 unsigned int realtime:1;
939 unsigned int found:1;
940 unsigned int relativeperiodicannounce:1;
941 enum empty_conditions joinempty;
942 enum empty_conditions leavewhenempty;
943 int announcepositionlimit; /*!< How many positions we announce? */
944 int announcefrequency; /*!< How often to announce their position */
945 int minannouncefrequency; /*!< The minimum number of seconds between position announcements (def. 15) */
946 int periodicannouncefrequency; /*!< How often to play periodic announcement */
947 int numperiodicannounce; /*!< The number of periodic announcements configured */
948 int randomperiodicannounce; /*!< Are periodic announcments randomly chosen */
949 int roundingseconds; /*!< How many seconds do we round to? */
950 int holdtime; /*!< Current avg holdtime, based on an exponential average */
951 int talktime; /*!< Current avg talktime, based on the same exponential average */
952 int callscompleted; /*!< Number of queue calls completed */
953 int callsabandoned; /*!< Number of queue calls abandoned */
954 int servicelevel; /*!< seconds setting for servicelevel*/
955 int callscompletedinsl; /*!< Number of calls answered with servicelevel*/
956 char monfmt[8]; /*!< Format to use when recording calls */
957 int montype; /*!< Monitor type Monitor vs. MixMonitor */
958 int count; /*!< How many entries */
959 int maxlen; /*!< Max number of entries */
960 int wrapuptime; /*!< Wrapup Time */
961 int penaltymemberslimit; /*!< Disregard penalty when queue has fewer than this many members */
963 int retry; /*!< Retry calling everyone after this amount of time */
964 int timeout; /*!< How long to wait for an answer */
965 int weight; /*!< Respective weight */
966 int autopause; /*!< Auto pause queue members if they fail to answer */
967 int timeoutpriority; /*!< Do we allow a fraction of the timeout to occur for a ring? */
969 /* Queue strategy things */
970 int rrpos; /*!< Round Robin - position */
971 int memberdelay; /*!< Seconds to delay connecting member to caller */
972 int autofill; /*!< Ignore the head call status and ring an available agent */
974 struct ao2_container *members; /*!< Head of the list of members */
976 * \brief Number of members _logged in_
977 * \note There will be members in the members container that are not logged
978 * in, so this can not simply be replaced with ao2_container_count().
981 struct queue_ent *head; /*!< Head of the list of callers */
982 AST_LIST_ENTRY(call_queue) list; /*!< Next call queue */
983 AST_LIST_HEAD_NOLOCK(, penalty_rule) rules; /*!< The list of penalty rules to invoke */
988 AST_LIST_HEAD_NOLOCK(,penalty_rule) rules;
989 AST_LIST_ENTRY(rule_list) list;
992 static AST_LIST_HEAD_STATIC(rule_lists, rule_list);
994 static struct ao2_container *queues;
996 static void update_realtime_members(struct call_queue *q);
997 static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
999 static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
1000 /*! \brief sets the QUEUESTATUS channel variable */
1001 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
1005 for (i = 0; i < ARRAY_LEN(queue_results); i++) {
1006 if (queue_results[i].id == res) {
1007 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
1013 static const char *int2strat(int strategy)
1017 for (x = 0; x < ARRAY_LEN(strategies); x++) {
1018 if (strategy == strategies[x].strategy)
1019 return strategies[x].name;
1025 static int strat2int(const char *strategy)
1029 for (x = 0; x < ARRAY_LEN(strategies); x++) {
1030 if (!strcasecmp(strategy, strategies[x].name))
1031 return strategies[x].strategy;
1037 static int queue_hash_cb(const void *obj, const int flags)
1039 const struct call_queue *q = obj;
1041 return ast_str_case_hash(q->name);
1044 static int queue_cmp_cb(void *obj, void *arg, int flags)
1046 struct call_queue *q = obj, *q2 = arg;
1047 return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0;
1050 #ifdef REF_DEBUG_ONLY_QUEUES
1051 #define queue_ref(a) __ao2_ref_debug(a,1,"",__FILE__,__LINE__,__PRETTY_FUNCTION__)
1052 #define queue_unref(a) __ao2_ref_debug(a,-1,"",__FILE__,__LINE__,__PRETTY_FUNCTION__)
1053 #define queue_t_ref(a,b) __ao2_ref_debug(a,1,b,__FILE__,__LINE__,__PRETTY_FUNCTION__)
1054 #define queue_t_unref(a,b) __ao2_ref_debug(a,-1,b,__FILE__,__LINE__,__PRETTY_FUNCTION__)
1055 #define queues_t_link(c,q,tag) __ao2_link_debug(c,q,tag,__FILE__,__LINE__,__PRETTY_FUNCTION__)
1056 #define queues_t_unlink(c,q,tag) __ao2_unlink_debug(c,q,tag,__FILE__,__LINE__,__PRETTY_FUNCTION__)
1058 #define queue_t_ref(a,b) queue_ref(a)
1059 #define queue_t_unref(a,b) queue_unref(a)
1060 #define queues_t_link(c,q,tag) ao2_t_link(c,q,tag)
1061 #define queues_t_unlink(c,q,tag) ao2_t_unlink(c,q,tag)
1062 static inline struct call_queue *queue_ref(struct call_queue *q)
1068 static inline struct call_queue *queue_unref(struct call_queue *q)
1075 /*! \brief Set variables of queue */
1076 static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
1078 char interfacevar[256]="";
1081 if (q->setqueuevar) {
1083 if (q->callscompleted > 0)
1084 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
1086 snprintf(interfacevar, sizeof(interfacevar),
1087 "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
1088 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned, q->servicelevel, sl);
1090 pbx_builtin_setvar_multiple(chan, interfacevar);
1094 /*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
1095 static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
1097 struct queue_ent *cur;
1110 /* every queue_ent must have a reference to it's parent call_queue, this
1111 * reference does not go away until the end of the queue_ent's life, meaning
1112 * that even when the queue_ent leaves the call_queue this ref must remain. */
1115 new->pos = ++(*pos);
1119 /*! \brief Check if members are available
1121 * This function checks to see if members are available to be called. If any member
1122 * is available, the function immediately returns 0. If no members are available,
1123 * then -1 is returned.
1125 static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, enum empty_conditions conditions)
1127 struct member *member;
1128 struct ao2_iterator mem_iter;
1131 mem_iter = ao2_iterator_init(q->members, 0);
1132 for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
1133 if ((max_penalty && (member->penalty > max_penalty)) || (min_penalty && (member->penalty < min_penalty))) {
1134 if (conditions & QUEUE_EMPTY_PENALTY) {
1135 ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
1140 switch (member->status) {
1141 case AST_DEVICE_INVALID:
1142 if (conditions & QUEUE_EMPTY_INVALID) {
1143 ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername);
1146 case AST_DEVICE_UNAVAILABLE:
1147 if (conditions & QUEUE_EMPTY_UNAVAILABLE) {
1148 ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername);
1151 case AST_DEVICE_INUSE:
1152 if (conditions & QUEUE_EMPTY_INUSE) {
1153 ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername);
1156 case AST_DEVICE_UNKNOWN:
1157 if (conditions & QUEUE_EMPTY_UNKNOWN) {
1158 ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername);
1162 if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) {
1163 ast_debug(4, "%s is unavailable because he is paused'\n", member->membername);
1165 } else if ((conditions & QUEUE_EMPTY_WRAPUP) && member->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < member->lastcall)) {
1166 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);
1170 ao2_ref(member, -1);
1171 ao2_iterator_destroy(&mem_iter);
1172 ast_debug(4, "%s is available.\n", member->membername);
1178 ao2_iterator_destroy(&mem_iter);
1184 struct statechange {
1185 AST_LIST_ENTRY(statechange) entry;
1190 /*! \brief set a member's status based on device state of that member's state_interface.
1192 * Lock interface list find sc, iterate through each queues queue_member list for member to
1193 * update state inside queues
1195 static int update_status(struct call_queue *q, struct member *m, const int status)
1199 if (q->maskmemberstatus)
1202 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
1205 "MemberName: %s\r\n"
1206 "Membership: %s\r\n"
1208 "CallsTaken: %d\r\n"
1212 q->name, m->interface, m->membername, m->dynamic ? "dynamic" : m->realtime ? "realtime" : "static",
1213 m->penalty, m->calls, (int)m->lastcall, m->status, m->paused
1219 /*! \brief set a member's status based on device state of that member's interface*/
1220 static int handle_statechange(void *datap)
1222 struct statechange *sc = datap;
1223 struct ao2_iterator miter, qiter;
1225 struct call_queue *q;
1226 char interface[80], *slash_pos;
1229 qiter = ao2_iterator_init(queues, 0);
1230 while ((q = ao2_t_iterator_next(&qiter, "Iterate over queues"))) {
1233 miter = ao2_iterator_init(q->members, 0);
1234 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
1235 ast_copy_string(interface, m->state_interface, sizeof(interface));
1237 if ((slash_pos = strchr(interface, '/')))
1238 if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/')))
1241 if (!strcasecmp(interface, sc->dev)) {
1243 update_status(q, m, sc->state);
1248 ao2_iterator_destroy(&miter);
1251 queue_t_unref(q, "Done with iterator");
1253 ao2_iterator_destroy(&qiter);
1256 ast_debug(1, "Device '%s' changed to state '%d' (%s)\n", sc->dev, sc->state, ast_devstate2str(sc->state));
1258 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));
1264 static void device_state_cb(const struct ast_event *event, void *unused)
1266 enum ast_device_state state;
1268 struct statechange *sc;
1271 state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
1272 device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
1274 if (ast_strlen_zero(device)) {
1275 ast_log(LOG_ERROR, "Received invalid event that had no device IE\n");
1278 datapsize = sizeof(*sc) + strlen(device) + 1;
1279 if (!(sc = ast_calloc(1, datapsize))) {
1280 ast_log(LOG_ERROR, "failed to calloc a state change struct\n");
1284 strcpy(sc->dev, device);
1285 if (ast_taskprocessor_push(devicestate_tps, handle_statechange, sc) < 0) {
1290 /*! \brief Helper function which converts from extension state to device state values */
1291 static int extensionstate2devicestate(int state)
1294 case AST_EXTENSION_NOT_INUSE:
1295 state = AST_DEVICE_NOT_INUSE;
1297 case AST_EXTENSION_INUSE:
1298 state = AST_DEVICE_INUSE;
1300 case AST_EXTENSION_BUSY:
1301 state = AST_DEVICE_BUSY;
1303 case AST_EXTENSION_RINGING:
1304 state = AST_DEVICE_RINGING;
1306 case AST_EXTENSION_ONHOLD:
1307 state = AST_DEVICE_ONHOLD;
1309 case AST_EXTENSION_UNAVAILABLE:
1310 state = AST_DEVICE_UNAVAILABLE;
1312 case AST_EXTENSION_REMOVED:
1313 case AST_EXTENSION_DEACTIVATED:
1315 state = AST_DEVICE_INVALID;
1322 static int extension_state_cb(char *context, char *exten, enum ast_extension_states state, void *data)
1324 struct ao2_iterator miter, qiter;
1326 struct call_queue *q;
1327 int found = 0, device_state = extensionstate2devicestate(state);
1329 qiter = ao2_iterator_init(queues, 0);
1330 while ((q = ao2_t_iterator_next(&qiter, "Iterate through queues"))) {
1333 miter = ao2_iterator_init(q->members, 0);
1334 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
1335 if (!strcmp(m->state_context, context) && !strcmp(m->state_exten, exten)) {
1336 update_status(q, m, device_state);
1342 ao2_iterator_destroy(&miter);
1345 queue_t_unref(q, "Done with iterator");
1347 ao2_iterator_destroy(&qiter);
1350 ast_debug(1, "Extension '%s@%s' changed to state '%d' (%s)\n", exten, context, device_state, ast_devstate2str(device_state));
1352 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",
1353 exten, context, device_state, ast_devstate2str(device_state));
1359 /*! \brief Return the current state of a member */
1360 static int get_queue_member_status(struct member *cur)
1362 return ast_strlen_zero(cur->state_exten) ? ast_device_state(cur->state_interface) : extensionstate2devicestate(ast_extension_state(NULL, cur->state_context, cur->state_exten));
1365 /*! \brief allocate space for new queue member and set fields based on parameters passed */
1366 static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface)
1370 if ((cur = ao2_alloc(sizeof(*cur), NULL))) {
1371 cur->penalty = penalty;
1372 cur->paused = paused;
1373 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
1374 if (!ast_strlen_zero(state_interface))
1375 ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface));
1377 ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface));
1378 if (!ast_strlen_zero(membername))
1379 ast_copy_string(cur->membername, membername, sizeof(cur->membername));
1381 ast_copy_string(cur->membername, interface, sizeof(cur->membername));
1382 if (!strchr(cur->interface, '/'))
1383 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
1384 if (!strncmp(cur->state_interface, "hint:", 5)) {
1385 char *tmp = ast_strdupa(cur->state_interface), *context = tmp;
1386 char *exten = strsep(&context, "@") + 5;
1388 ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten));
1389 ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context));
1391 cur->status = get_queue_member_status(cur);
1398 static int compress_char(const char c)
1408 static int member_hash_fn(const void *obj, const int flags)
1410 const struct member *mem = obj;
1411 const char *chname = strchr(mem->interface, '/');
1414 chname = mem->interface;
1415 for (i = 0; i < 5 && chname[i]; i++)
1416 ret += compress_char(chname[i]) << (i * 6);
1420 static int member_cmp_fn(void *obj1, void *obj2, int flags)
1422 struct member *mem1 = obj1, *mem2 = obj2;
1423 return strcasecmp(mem1->interface, mem2->interface) ? 0 : CMP_MATCH | CMP_STOP;
1427 * \brief Initialize Queue default values.
1428 * \note the queue's lock must be held before executing this function
1430 static void init_queue(struct call_queue *q)
1433 struct penalty_rule *pr_iter;
1436 q->retry = DEFAULT_RETRY;
1437 q->timeout = DEFAULT_TIMEOUT;
1439 q->announcefrequency = 0;
1440 q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY;
1441 q->announceholdtime = 1;
1442 q->announcepositionlimit = 10; /* Default 10 positions */
1443 q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */
1444 q->roundingseconds = 0; /* Default - don't announce seconds */
1445 q->servicelevel = 0;
1447 q->setinterfacevar = 0;
1449 q->setqueueentryvar = 0;
1450 q->autofill = autofill_default;
1451 q->montype = montype_default;
1452 q->monfmt[0] = '\0';
1453 q->reportholdtime = 0;
1455 q->penaltymemberslimit = 0;
1457 q->leavewhenempty = 0;
1459 q->maskmemberstatus = 0;
1460 q->eventwhencalled = 0;
1462 q->timeoutrestart = 0;
1463 q->periodicannouncefrequency = 0;
1464 q->randomperiodicannounce = 0;
1465 q->numperiodicannounce = 0;
1466 q->timeoutpriority = TIMEOUT_PRIORITY_APP;
1468 if (q->strategy == QUEUE_STRATEGY_LINEAR)
1469 /* linear strategy depends on order, so we have to place all members in a single bucket */
1470 q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn);
1472 q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
1476 ast_string_field_set(q, sound_next, "queue-youarenext");
1477 ast_string_field_set(q, sound_thereare, "queue-thereare");
1478 ast_string_field_set(q, sound_calls, "queue-callswaiting");
1479 ast_string_field_set(q, queue_quantity1, "queue-quantity1");
1480 ast_string_field_set(q, queue_quantity2, "queue-quantity2");
1481 ast_string_field_set(q, sound_holdtime, "queue-holdtime");
1482 ast_string_field_set(q, sound_minutes, "queue-minutes");
1483 ast_string_field_set(q, sound_minute, "queue-minute");
1484 ast_string_field_set(q, sound_seconds, "queue-seconds");
1485 ast_string_field_set(q, sound_thanks, "queue-thankyou");
1486 ast_string_field_set(q, sound_reporthold, "queue-reporthold");
1488 if ((q->sound_periodicannounce[0] = ast_str_create(32)))
1489 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
1491 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
1492 if (q->sound_periodicannounce[i])
1493 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
1496 while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list)))
1500 static void clear_queue(struct call_queue *q)
1503 q->callscompleted = 0;
1504 q->callsabandoned = 0;
1505 q->callscompletedinsl = 0;
1511 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
1512 while ((mem = ao2_iterator_next(&mem_iter))) {
1516 ao2_iterator_destroy(&mem_iter);
1521 * \brief Change queue penalty by adding rule.
1523 * Check rule for errors with time or fomatting, see if rule is relative to rest
1524 * of queue, iterate list of rules to find correct insertion point, insert and return.
1525 * \retval -1 on failure
1526 * \retval 0 on success
1527 * \note Call this with the rule_lists locked
1529 static int insert_penaltychange (const char *list_name, const char *content, const int linenum)
1531 char *timestr, *maxstr, *minstr, *contentdup;
1532 struct penalty_rule *rule = NULL, *rule_iter;
1533 struct rule_list *rl_iter;
1534 int penaltychangetime, inserted = 0;
1536 if (!(rule = ast_calloc(1, sizeof(*rule)))) {
1540 contentdup = ast_strdupa(content);
1542 if (!(maxstr = strchr(contentdup, ','))) {
1543 ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum);
1549 timestr = contentdup;
1551 if ((penaltychangetime = atoi(timestr)) < 0) {
1552 ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum);
1557 rule->time = penaltychangetime;
1559 if ((minstr = strchr(maxstr,',')))
1562 /* The last check will evaluate true if either no penalty change is indicated for a given rule
1563 * OR if a min penalty change is indicated but no max penalty change is */
1564 if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') {
1565 rule->max_relative = 1;
1568 rule->max_value = atoi(maxstr);
1570 if (!ast_strlen_zero(minstr)) {
1571 if (*minstr == '+' || *minstr == '-')
1572 rule->min_relative = 1;
1573 rule->min_value = atoi(minstr);
1574 } else /*there was no minimum specified, so assume this means no change*/
1575 rule->min_relative = 1;
1577 /*We have the rule made, now we need to insert it where it belongs*/
1578 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){
1579 if (strcasecmp(rl_iter->name, list_name))
1582 AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) {
1583 if (rule->time < rule_iter->time) {
1584 AST_LIST_INSERT_BEFORE_CURRENT(rule, list);
1589 AST_LIST_TRAVERSE_SAFE_END;
1592 AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list);
1599 static void parse_empty_options(const char *value, enum empty_conditions *empty, int joinempty)
1601 char *value_copy = ast_strdupa(value);
1602 char *option = NULL;
1603 while ((option = strsep(&value_copy, ","))) {
1604 if (!strcasecmp(option, "paused")) {
1605 *empty |= QUEUE_EMPTY_PAUSED;
1606 } else if (!strcasecmp(option, "penalty")) {
1607 *empty |= QUEUE_EMPTY_PENALTY;
1608 } else if (!strcasecmp(option, "inuse")) {
1609 *empty |= QUEUE_EMPTY_INUSE;
1610 } else if (!strcasecmp(option, "ringing")) {
1611 *empty |= QUEUE_EMPTY_RINGING;
1612 } else if (!strcasecmp(option, "invalid")) {
1613 *empty |= QUEUE_EMPTY_INVALID;
1614 } else if (!strcasecmp(option, "wrapup")) {
1615 *empty |= QUEUE_EMPTY_WRAPUP;
1616 } else if (!strcasecmp(option, "unavailable")) {
1617 *empty |= QUEUE_EMPTY_UNAVAILABLE;
1618 } else if (!strcasecmp(option, "unknown")) {
1619 *empty |= QUEUE_EMPTY_UNKNOWN;
1620 } else if (!strcasecmp(option, "loose")) {
1621 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID);
1622 } else if (!strcasecmp(option, "strict")) {
1623 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED | QUEUE_EMPTY_UNAVAILABLE);
1624 } else if ((ast_false(option) && joinempty) || (ast_true(option) && !joinempty)) {
1625 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED);
1626 } else if ((ast_false(option) && !joinempty) || (ast_true(option) && joinempty)) {
1629 ast_log(LOG_WARNING, "Unknown option %s for '%s'\n", option, joinempty ? "joinempty" : "leavewhenempty");
1634 /*! \brief Configure a queue parameter.
1636 * The failunknown flag is set for config files (and static realtime) to show
1637 * errors for unknown parameters. It is cleared for dynamic realtime to allow
1638 * extra fields in the tables.
1639 * \note For error reporting, line number is passed for .conf static configuration,
1640 * for Realtime queues, linenum is -1.
1642 static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
1644 if (!strcasecmp(param, "musicclass") ||
1645 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
1646 ast_string_field_set(q, moh, val);
1647 } else if (!strcasecmp(param, "announce")) {
1648 ast_string_field_set(q, announce, val);
1649 } else if (!strcasecmp(param, "context")) {
1650 ast_string_field_set(q, context, val);
1651 } else if (!strcasecmp(param, "timeout")) {
1652 q->timeout = atoi(val);
1654 q->timeout = DEFAULT_TIMEOUT;
1655 } else if (!strcasecmp(param, "ringinuse")) {
1656 q->ringinuse = ast_true(val);
1657 } else if (!strcasecmp(param, "setinterfacevar")) {
1658 q->setinterfacevar = ast_true(val);
1659 } else if (!strcasecmp(param, "setqueuevar")) {
1660 q->setqueuevar = ast_true(val);
1661 } else if (!strcasecmp(param, "setqueueentryvar")) {
1662 q->setqueueentryvar = ast_true(val);
1663 } else if (!strcasecmp(param, "monitor-format")) {
1664 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
1665 } else if (!strcasecmp(param, "membermacro")) {
1666 ast_string_field_set(q, membermacro, val);
1667 } else if (!strcasecmp(param, "membergosub")) {
1668 ast_string_field_set(q, membergosub, val);
1669 } else if (!strcasecmp(param, "queue-youarenext")) {
1670 ast_string_field_set(q, sound_next, val);
1671 } else if (!strcasecmp(param, "queue-thereare")) {
1672 ast_string_field_set(q, sound_thereare, val);
1673 } else if (!strcasecmp(param, "queue-callswaiting")) {
1674 ast_string_field_set(q, sound_calls, val);
1675 } else if (!strcasecmp(param, "queue-quantity1")) {
1676 ast_string_field_set(q, queue_quantity1, val);
1677 } else if (!strcasecmp(param, "queue-quantity2")) {
1678 ast_string_field_set(q, queue_quantity2, val);
1679 } else if (!strcasecmp(param, "queue-holdtime")) {
1680 ast_string_field_set(q, sound_holdtime, val);
1681 } else if (!strcasecmp(param, "queue-minutes")) {
1682 ast_string_field_set(q, sound_minutes, val);
1683 } else if (!strcasecmp(param, "queue-minute")) {
1684 ast_string_field_set(q, sound_minute, val);
1685 } else if (!strcasecmp(param, "queue-seconds")) {
1686 ast_string_field_set(q, sound_seconds, val);
1687 } else if (!strcasecmp(param, "queue-thankyou")) {
1688 ast_string_field_set(q, sound_thanks, val);
1689 } else if (!strcasecmp(param, "queue-callerannounce")) {
1690 ast_string_field_set(q, sound_callerannounce, val);
1691 } else if (!strcasecmp(param, "queue-reporthold")) {
1692 ast_string_field_set(q, sound_reporthold, val);
1693 } else if (!strcasecmp(param, "announce-frequency")) {
1694 q->announcefrequency = atoi(val);
1695 } else if (!strcasecmp(param, "min-announce-frequency")) {
1696 q->minannouncefrequency = atoi(val);
1697 ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name);
1698 } else if (!strcasecmp(param, "announce-round-seconds")) {
1699 q->roundingseconds = atoi(val);
1700 /* Rounding to any other values just doesn't make sense... */
1701 if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10
1702 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) {
1704 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
1705 "using 0 instead for queue '%s' at line %d of queues.conf\n",
1706 val, param, q->name, linenum);
1708 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
1709 "using 0 instead for queue '%s'\n", val, param, q->name);
1711 q->roundingseconds=0;
1713 } else if (!strcasecmp(param, "announce-holdtime")) {
1714 if (!strcasecmp(val, "once"))
1715 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
1716 else if (ast_true(val))
1717 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
1719 q->announceholdtime = 0;
1720 } else if (!strcasecmp(param, "announce-position")) {
1721 if (!strcasecmp(val, "limit"))
1722 q->announceposition = ANNOUNCEPOSITION_LIMIT;
1723 else if (!strcasecmp(val, "more"))
1724 q->announceposition = ANNOUNCEPOSITION_MORE_THAN;
1725 else if (ast_true(val))
1726 q->announceposition = ANNOUNCEPOSITION_YES;
1728 q->announceposition = ANNOUNCEPOSITION_NO;
1729 } else if (!strcasecmp(param, "announce-position-limit")) {
1730 q->announcepositionlimit = atoi(val);
1731 } else if (!strcasecmp(param, "periodic-announce")) {
1732 if (strchr(val, ',')) {
1733 char *s, *buf = ast_strdupa(val);
1736 while ((s = strsep(&buf, ",|"))) {
1737 if (!q->sound_periodicannounce[i])
1738 q->sound_periodicannounce[i] = ast_str_create(16);
1739 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s);
1741 if (i == MAX_PERIODIC_ANNOUNCEMENTS)
1744 q->numperiodicannounce = i;
1746 ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val);
1747 q->numperiodicannounce = 1;
1749 } else if (!strcasecmp(param, "periodic-announce-frequency")) {
1750 q->periodicannouncefrequency = atoi(val);
1751 } else if (!strcasecmp(param, "relative-periodic-announce")) {
1752 q->relativeperiodicannounce = ast_true(val);
1753 } else if (!strcasecmp(param, "random-periodic-announce")) {
1754 q->randomperiodicannounce = ast_true(val);
1755 } else if (!strcasecmp(param, "retry")) {
1756 q->retry = atoi(val);
1758 q->retry = DEFAULT_RETRY;
1759 } else if (!strcasecmp(param, "wrapuptime")) {
1760 q->wrapuptime = atoi(val);
1761 } else if (!strcasecmp(param, "penaltymemberslimit")) {
1762 if ((sscanf(val, "%10d", &q->penaltymemberslimit) != 1)) {
1763 q->penaltymemberslimit = 0;
1765 } else if (!strcasecmp(param, "autofill")) {
1766 q->autofill = ast_true(val);
1767 } else if (!strcasecmp(param, "monitor-type")) {
1768 if (!strcasecmp(val, "mixmonitor"))
1770 } else if (!strcasecmp(param, "autopause")) {
1771 q->autopause = ast_true(val);
1772 } else if (!strcasecmp(param, "maxlen")) {
1773 q->maxlen = atoi(val);
1776 } else if (!strcasecmp(param, "servicelevel")) {
1777 q->servicelevel= atoi(val);
1778 } else if (!strcasecmp(param, "strategy")) {
1781 /* We are a static queue and already have set this, no need to do it again */
1785 strategy = strat2int(val);
1787 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
1789 q->strategy = QUEUE_STRATEGY_RINGALL;
1791 if (strategy == q->strategy) {
1794 if (strategy == QUEUE_STRATEGY_LINEAR) {
1795 ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n");
1798 q->strategy = strategy;
1799 } else if (!strcasecmp(param, "joinempty")) {
1800 parse_empty_options(val, &q->joinempty, 1);
1801 } else if (!strcasecmp(param, "leavewhenempty")) {
1802 parse_empty_options(val, &q->leavewhenempty, 0);
1803 } else if (!strcasecmp(param, "eventmemberstatus")) {
1804 q->maskmemberstatus = !ast_true(val);
1805 } else if (!strcasecmp(param, "eventwhencalled")) {
1806 if (!strcasecmp(val, "vars")) {
1807 q->eventwhencalled = QUEUE_EVENT_VARIABLES;
1809 q->eventwhencalled = ast_true(val) ? 1 : 0;
1811 } else if (!strcasecmp(param, "reportholdtime")) {
1812 q->reportholdtime = ast_true(val);
1813 } else if (!strcasecmp(param, "memberdelay")) {
1814 q->memberdelay = atoi(val);
1815 } else if (!strcasecmp(param, "weight")) {
1816 q->weight = atoi(val);
1817 } else if (!strcasecmp(param, "timeoutrestart")) {
1818 q->timeoutrestart = ast_true(val);
1819 } else if (!strcasecmp(param, "defaultrule")) {
1820 ast_string_field_set(q, defaultrule, val);
1821 } else if (!strcasecmp(param, "timeoutpriority")) {
1822 if (!strcasecmp(val, "conf")) {
1823 q->timeoutpriority = TIMEOUT_PRIORITY_CONF;
1825 q->timeoutpriority = TIMEOUT_PRIORITY_APP;
1827 } else if (failunknown) {
1829 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
1830 q->name, param, linenum);
1832 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
1838 * \brief Find rt member record to update otherwise create one.
1840 * Search for member in queue, if found update penalty/paused state,
1841 * if no memeber exists create one flag it as a RT member and add to queue member list.
1843 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)
1846 struct ao2_iterator mem_iter;
1852 penalty = atoi(penalty_str);
1858 paused = atoi(paused_str);
1863 /* Find member by realtime uniqueid and update */
1864 mem_iter = ao2_iterator_init(q->members, 0);
1865 while ((m = ao2_iterator_next(&mem_iter))) {
1866 if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) {
1867 m->dead = 0; /* Do not delete this one. */
1868 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
1871 if (strcasecmp(state_interface, m->state_interface)) {
1872 ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
1874 m->penalty = penalty;
1881 ao2_iterator_destroy(&mem_iter);
1883 /* Create a new member */
1885 if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) {
1888 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
1889 ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", "");
1890 ao2_link(q->members, m);
1898 /*! \brief Iterate through queue's member list and delete them */
1899 static void free_members(struct call_queue *q, int all)
1901 /* Free non-dynamic members */
1903 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
1905 while ((cur = ao2_iterator_next(&mem_iter))) {
1906 if (all || !cur->dynamic) {
1907 ao2_unlink(q->members, cur);
1912 ao2_iterator_destroy(&mem_iter);
1915 /*! \brief Free queue's member list then its string fields */
1916 static void destroy_queue(void *obj)
1918 struct call_queue *q = obj;
1922 ast_string_field_free_memory(q);
1923 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
1924 if (q->sound_periodicannounce[i])
1925 free(q->sound_periodicannounce[i]);
1927 ao2_ref(q->members, -1);
1930 static struct call_queue *alloc_queue(const char *queuename)
1932 struct call_queue *q;
1934 if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) {
1935 if (ast_string_field_init(q, 64)) {
1936 queue_t_unref(q, "String field allocation failed");
1939 ast_string_field_set(q, name, queuename);
1945 * \brief Reload a single queue via realtime.
1947 * Check for statically defined queue first, check if deleted RT queue,
1948 * check for new RT queue, if queue vars are not defined init them with defaults.
1949 * reload RT queue vars, set RT queue members dead and reload them, return finished queue.
1950 * \retval the queue,
1951 * \retval NULL if it doesn't exist.
1952 * \note Should be called with the "queues" container locked.
1954 static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
1956 struct ast_variable *v;
1957 struct call_queue *q, tmpq = {
1961 struct ao2_iterator mem_iter;
1962 char *interface = NULL;
1963 const char *tmp_name;
1965 char tmpbuf[64]; /* Must be longer than the longest queue param name. */
1967 /* Static queues override realtime. */
1968 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Check if static queue exists"))) {
1973 queue_t_unref(q, "Queue is dead; can't return it");
1976 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
1981 } else if (!member_config)
1982 /* Not found in the list, and it's not realtime ... */
1985 /* Check if queue is defined in realtime. */
1987 /* Delete queue from in-core list if it has been deleted in realtime. */
1989 /*! \note Hmm, can't seem to distinguish a DB failure from a not
1990 found condition... So we might delete an in-core queue
1991 in case of DB failure. */
1992 ast_debug(1, "Queue %s not found in realtime.\n", queuename);
1995 /* Delete if unused (else will be deleted when last caller leaves). */
1996 queues_t_unlink(queues, q, "Unused; removing from container");
1998 queue_t_unref(q, "Queue is dead; can't return it");
2003 /* Create a new queue if an in-core entry does not exist yet. */
2005 struct ast_variable *tmpvar = NULL;
2006 if (!(q = alloc_queue(queuename)))
2012 /*Before we initialize the queue, we need to set the strategy, so that linear strategy
2013 * will allocate the members properly
2015 for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) {
2016 if (!strcasecmp(tmpvar->name, "strategy")) {
2017 q->strategy = strat2int(tmpvar->value);
2018 if (q->strategy < 0) {
2019 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
2020 tmpvar->value, q->name);
2021 q->strategy = QUEUE_STRATEGY_RINGALL;
2026 /* We traversed all variables and didn't find a strategy */
2028 q->strategy = QUEUE_STRATEGY_RINGALL;
2029 queues_t_link(queues, q, "Add queue to container");
2031 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
2033 memset(tmpbuf, 0, sizeof(tmpbuf));
2034 for (v = queue_vars; v; v = v->next) {
2035 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
2036 if ((tmp = strchr(v->name, '_'))) {
2037 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
2040 while ((tmp = strchr(tmp, '_')))
2045 if (!ast_strlen_zero(v->value)) {
2046 /* Don't want to try to set the option if the value is empty */
2047 queue_set_param(q, tmp_name, v->value, -1, 0);
2051 /* Temporarily set realtime members dead so we can detect deleted ones.
2052 * Also set the membercount correctly for realtime*/
2053 mem_iter = ao2_iterator_init(q->members, 0);
2054 while ((m = ao2_iterator_next(&mem_iter))) {
2060 ao2_iterator_destroy(&mem_iter);
2062 while ((interface = ast_category_browse(member_config, interface))) {
2063 rt_handle_member_record(q, interface,
2064 ast_variable_retrieve(member_config, interface, "uniqueid"),
2065 S_OR(ast_variable_retrieve(member_config, interface, "membername"),interface),
2066 ast_variable_retrieve(member_config, interface, "penalty"),
2067 ast_variable_retrieve(member_config, interface, "paused"),
2068 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface));
2071 /* Delete all realtime members that have been deleted in DB. */
2072 mem_iter = ao2_iterator_init(q->members, 0);
2073 while ((m = ao2_iterator_next(&mem_iter))) {
2075 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
2076 ao2_unlink(q->members, m);
2081 ao2_iterator_destroy(&mem_iter);
2088 static struct call_queue *load_realtime_queue(const char *queuename)
2090 struct ast_variable *queue_vars;
2091 struct ast_config *member_config = NULL;
2092 struct call_queue *q = NULL, tmpq = {
2095 int prev_weight = 0;
2097 /* Find the queue in the in-core list first. */
2098 q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Look for queue in memory first");
2100 if (!q || q->realtime) {
2101 /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all
2102 queue operations while waiting for the DB.
2104 This will be two separate database transactions, so we might
2105 see queue parameters as they were before another process
2106 changed the queue and member list as it was after the change.
2107 Thus we might see an empty member list when a queue is
2108 deleted. In practise, this is unlikely to cause a problem. */
2110 queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL);
2112 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL);
2113 if (!member_config) {
2114 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
2115 ast_variables_destroy(queue_vars);
2120 prev_weight = q->weight ? 1 : 0;
2125 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
2126 if (member_config) {
2127 ast_config_destroy(member_config);
2130 ast_variables_destroy(queue_vars);
2132 /* update the use_weight value if the queue's has gained or lost a weight */
2134 if (!q->weight && prev_weight) {
2135 ast_atomic_fetchadd_int(&use_weight, -1);
2137 if (q->weight && !prev_weight) {
2138 ast_atomic_fetchadd_int(&use_weight, +1);
2141 /* Other cases will end up with the proper value for use_weight */
2145 update_realtime_members(q);
2150 static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
2154 if (ast_strlen_zero(mem->rt_uniqueid))
2157 if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) > 0)
2164 static void update_realtime_members(struct call_queue *q)
2166 struct ast_config *member_config = NULL;
2168 char *interface = NULL;
2169 struct ao2_iterator mem_iter;
2171 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , SENTINEL))) {
2172 /*This queue doesn't have realtime members*/
2173 ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name);
2180 /* Temporarily set realtime members dead so we can detect deleted ones.*/
2181 mem_iter = ao2_iterator_init(q->members, 0);
2182 while ((m = ao2_iterator_next(&mem_iter))) {
2187 ao2_iterator_destroy(&mem_iter);
2189 while ((interface = ast_category_browse(member_config, interface))) {
2190 rt_handle_member_record(q, interface,
2191 ast_variable_retrieve(member_config, interface, "uniqueid"),
2192 S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
2193 ast_variable_retrieve(member_config, interface, "penalty"),
2194 ast_variable_retrieve(member_config, interface, "paused"),
2195 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface));
2198 /* Delete all realtime members that have been deleted in DB. */
2199 mem_iter = ao2_iterator_init(q->members, 0);
2200 while ((m = ao2_iterator_next(&mem_iter))) {
2202 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
2203 ao2_unlink(q->members, m);
2208 ao2_iterator_destroy(&mem_iter);
2211 ast_config_destroy(member_config);
2214 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
2216 struct call_queue *q;
2217 struct queue_ent *cur, *prev = NULL;
2222 if (!(q = load_realtime_queue(queuename)))
2228 /* This is our one */
2231 if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, q->joinempty))) {
2232 *reason = QUEUE_JOINEMPTY;
2238 if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen))
2239 *reason = QUEUE_FULL;
2240 else if (*reason == QUEUE_UNKNOWN) {
2241 /* There's space for us, put us at the right position inside
2243 * Take into account the priority of the calling user */
2248 /* We have higher priority than the current user, enter
2249 * before him, after all the other users with priority
2250 * higher or equal to our priority. */
2251 if ((!inserted) && (qe->prio > cur->prio)) {
2252 insert_entry(q, prev, qe, &pos);
2255 /* <= is necessary for the position comparison because it may not be possible to enter
2256 * at our desired position since higher-priority callers may have taken the position we want
2258 if (!inserted && (qe->prio <= cur->prio) && position && (position <= pos + 1)) {
2259 insert_entry(q, prev, qe, &pos);
2260 /*pos is incremented inside insert_entry, so don't need to add 1 here*/
2261 if (position < pos) {
2262 ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos);
2270 /* No luck, join at the end of the queue */
2272 insert_entry(q, prev, qe, &pos);
2273 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
2274 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
2275 ast_copy_string(qe->context, q->context, sizeof(qe->context));
2278 ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Join",
2279 "Channel: %s\r\nCallerIDNum: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
2281 S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */
2282 S_OR(qe->chan->cid.cid_name, "unknown"),
2283 q->name, qe->pos, q->count, qe->chan->uniqueid );
2284 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
2292 static int play_file(struct ast_channel *chan, const char *filename)
2296 if (ast_strlen_zero(filename)) {
2300 ast_stopstream(chan);
2302 res = ast_streamfile(chan, filename, chan->language);
2304 res = ast_waitstream(chan, AST_DIGIT_ANY);
2306 ast_stopstream(chan);
2312 * \brief Check for valid exit from queue via goto
2313 * \retval 0 if failure
2314 * \retval 1 if successful
2316 static int valid_exit(struct queue_ent *qe, char digit)
2318 int digitlen = strlen(qe->digits);
2320 /* Prevent possible buffer overflow */
2321 if (digitlen < sizeof(qe->digits) - 2) {
2322 qe->digits[digitlen] = digit;
2323 qe->digits[digitlen + 1] = '\0';
2325 qe->digits[0] = '\0';
2329 /* If there's no context to goto, short-circuit */
2330 if (ast_strlen_zero(qe->context))
2333 /* If the extension is bad, then reset the digits to blank */
2334 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) {
2335 qe->digits[0] = '\0';
2339 /* We have an exact match */
2340 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
2341 qe->valid_digits = 1;
2342 /* Return 1 on a successful goto */
2349 static int say_position(struct queue_ent *qe, int ringing)
2351 int res = 0, avgholdmins, avgholdsecs, announceposition = 0;
2355 /* Let minannouncefrequency seconds pass between the start of each position announcement */
2357 if ((now - qe->last_pos) < qe->parent->minannouncefrequency)
2360 /* If either our position has changed, or we are over the freq timer, say position */
2361 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency))
2365 ast_indicate(qe->chan,-1);
2367 ast_moh_stop(qe->chan);
2370 if (qe->parent->announceposition == ANNOUNCEPOSITION_YES ||
2371 qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN ||
2372 (qe->parent->announceposition == ANNOUNCEPOSITION_LIMIT &&
2373 qe->pos <= qe->parent->announcepositionlimit))
2374 announceposition = 1;
2377 if (announceposition == 1) {
2378 /* Say we're next, if we are */
2380 res = play_file(qe->chan, qe->parent->sound_next);
2386 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){
2388 res = play_file(qe->chan, qe->parent->queue_quantity1);
2391 res = ast_say_number(qe->chan, qe->parent->announcepositionlimit, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */
2396 res = play_file(qe->chan, qe->parent->sound_thereare);
2399 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */
2403 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){
2405 res = play_file(qe->chan, qe->parent->queue_quantity2);
2409 res = play_file(qe->chan, qe->parent->sound_calls);
2415 /* Round hold time to nearest minute */
2416 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
2418 /* If they have specified a rounding then round the seconds as well */
2419 if (qe->parent->roundingseconds) {
2420 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
2421 avgholdsecs *= qe->parent->roundingseconds;
2426 ast_verb(3, "Hold time for %s is %d minute(s) %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
2428 /* If the hold time is >1 min, if it's enabled, and if it's not
2429 supposed to be only once and we have already said it, say it */
2430 if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime &&
2431 ((qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE && !qe->last_pos) ||
2432 !(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE))) {
2433 res = play_file(qe->chan, qe->parent->sound_holdtime);
2437 if (avgholdmins >= 1) {
2438 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL);
2442 if (avgholdmins == 1) {
2443 res = play_file(qe->chan, qe->parent->sound_minute);
2447 res = play_file(qe->chan, qe->parent->sound_minutes);
2452 if (avgholdsecs >= 1) {
2453 res = ast_say_number(qe->chan, avgholdmins > 1 ? avgholdsecs : avgholdmins * 60 + avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL);
2457 res = play_file(qe->chan, qe->parent->sound_seconds);
2461 } else if (qe->parent->announceholdtime && !qe->parent->announceposition) {
2466 if (qe->parent->announceposition) {
2467 ast_verb(3, "Told %s in %s their queue position (which was %d)\n",
2468 qe->chan->name, qe->parent->name, qe->pos);
2471 res = play_file(qe->chan, qe->parent->sound_thanks);
2475 if ((res > 0 && !valid_exit(qe, res)))
2478 /* Set our last_pos indicators */
2480 qe->last_pos_said = qe->pos;
2482 /* Don't restart music on hold if we're about to exit the caller from the queue */
2485 ast_indicate(qe->chan, AST_CONTROL_RINGING);
2487 ast_moh_start(qe->chan, qe->moh, NULL);
2493 static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
2497 /* Calculate holdtime using an exponential average */
2498 /* Thanks to SRT for this contribution */
2499 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
2501 ao2_lock(qe->parent);
2502 oldvalue = qe->parent->holdtime;
2503 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
2504 ao2_unlock(qe->parent);
2507 /*! \brief Caller leaving queue.
2509 * Search the queue to find the leaving client, if found remove from queue
2510 * create manager event, move others up the queue.
2512 static void leave_queue(struct queue_ent *qe)
2514 struct call_queue *q;
2515 struct queue_ent *current, *prev = NULL;
2516 struct penalty_rule *pr_iter;
2519 if (!(q = qe->parent))
2521 queue_t_ref(q, "Copy queue pointer from queue entry");
2525 for (current = q->head; current; current = current->next) {
2526 if (current == qe) {
2530 /* Take us out of the queue */
2531 ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Leave",
2532 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nPosition: %d\r\nUniqueid: %s\r\n",
2533 qe->chan->name, q->name, q->count, qe->pos, qe->chan->uniqueid);
2534 ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
2535 /* Take us out of the queue */
2537 prev->next = current->next;
2539 q->head = current->next;
2540 /* Free penalty rules */
2541 while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list)))
2543 snprintf(posstr, sizeof(posstr), "%d", qe->pos);
2544 pbx_builtin_setvar_helper(qe->chan, "QUEUEPOSITION", posstr);
2546 /* Renumber the people after us in the queue based on a new count */
2547 current->pos = ++pos;
2553 /*If the queue is a realtime queue, check to see if it's still defined in real time*/
2555 struct ast_variable *var;
2556 if (!(var = ast_load_realtime("queues", "name", q->name, SENTINEL))) {
2559 ast_variables_destroy(var);
2564 /* It's dead and nobody is in it, so kill it */
2565 queues_t_unlink(queues, q, "Queue is now dead; remove it from the container");
2567 /* unref the explicit ref earlier in the function */
2568 queue_t_unref(q, "Expire copied reference");
2571 /*! \brief Hang up a list of outgoing calls */
2572 static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere)
2574 struct callattempt *oo;
2577 /* If someone else answered the call we should indicate this in the CANCEL */
2578 /* Hangup any existing lines we have open */
2579 if (outgoing->chan && (outgoing->chan != exception || cancel_answered_elsewhere)) {
2580 if (exception || cancel_answered_elsewhere)
2581 ast_set_flag(outgoing->chan, AST_FLAG_ANSWERED_ELSEWHERE);
2582 ast_hangup(outgoing->chan);
2585 outgoing = outgoing->q_next;
2587 ao2_ref(oo->member, -1);
2593 * \brief Get the number of members available to accept a call.
2595 * \note The queue passed in should be locked prior to this function call
2597 * \param[in] q The queue for which we are couting the number of available members
2598 * \return Return the number of available members in queue q
2600 static int num_available_members(struct call_queue *q)
2604 struct ao2_iterator mem_iter;
2606 mem_iter = ao2_iterator_init(q->members, 0);
2607 while ((mem = ao2_iterator_next(&mem_iter))) {
2608 switch (mem->status) {
2609 case AST_DEVICE_INUSE:
2612 /* else fall through */
2613 case AST_DEVICE_NOT_INUSE:
2614 case AST_DEVICE_UNKNOWN:
2622 /* If autofill is not enabled or if the queue's strategy is ringall, then
2623 * we really don't care about the number of available members so much as we
2624 * do that there is at least one available.
2626 * In fact, we purposely will return from this function stating that only
2627 * one member is available if either of those conditions hold. That way,
2628 * functions which determine what action to take based on the number of available
2629 * members will operate properly. The reasoning is that even if multiple
2630 * members are available, only the head caller can actually be serviced.
2632 if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) {
2636 ao2_iterator_destroy(&mem_iter);
2641 /* traverse all defined queues which have calls waiting and contain this member
2642 return 0 if no other queue has precedence (higher weight) or 1 if found */
2643 static int compare_weight(struct call_queue *rq, struct member *member)
2645 struct call_queue *q;
2648 struct ao2_iterator queue_iter;
2650 /* q's lock and rq's lock already set by try_calling()
2651 * to solve deadlock */
2652 queue_iter = ao2_iterator_init(queues, 0);
2653 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
2654 if (q == rq) { /* don't check myself, could deadlock */
2655 queue_t_unref(q, "Done with iterator");
2659 if (q->count && q->members) {
2660 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
2661 ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
2662 if (q->weight > rq->weight && q->count >= num_available_members(q)) {
2663 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);
2670 queue_t_unref(q, "Done with iterator");
2675 ao2_iterator_destroy(&queue_iter);
2679 /*! \brief common hangup actions */
2680 static void do_hang(struct callattempt *o)
2683 ast_hangup(o->chan);
2687 /*! \brief convert "\n" to "\nVariable: " ready for manager to use */
2688 static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
2690 struct ast_str *buf = ast_str_thread_get(&ast_str_thread_global_buf, len + 1);
2693 if (pbx_builtin_serialize_variables(chan, &buf)) {
2696 /* convert "\n" to "\nVariable: " */
2697 strcpy(vars, "Variable: ");
2698 tmp = ast_str_buffer(buf);
2700 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) {
2703 if (tmp[i + 1] == '\0')
2705 if (tmp[i] == '\n') {
2709 ast_copy_string(&(vars[j]), "Variable: ", len - j);
2719 /* there are no channel variables; leave it blank */
2726 * \brief Part 2 of ring_one
2728 * Does error checking before attempting to request a channel and call a member.
2729 * This function is only called from ring_one().
2730 * Failure can occur if:
2733 * - Wrapup time not expired
2734 * - Priority by another queue
2736 * \retval 1 on success to reach a free agent
2737 * \retval 0 on failure to get agent.
2739 static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
2745 const char *macrocontext, *macroexten;
2747 /* on entry here, we know that tmp->chan == NULL */
2748 if ((tmp->lastqueue && tmp->lastqueue->wrapuptime && (time(NULL) - tmp->lastcall < tmp->lastqueue->wrapuptime)) ||
2749 (!tmp->lastqueue && qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime))) {
2750 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
2751 (tmp->lastqueue ? tmp->lastqueue->name : qe->parent->name), tmp->interface);
2753 ast_cdr_busy(qe->chan->cdr);
2754 tmp->stillgoing = 0;
2759 if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
2760 ast_debug(1, "%s in use, can't receive call\n", tmp->interface);
2762 ast_cdr_busy(qe->chan->cdr);
2763 tmp->stillgoing = 0;
2767 if (tmp->member->paused) {
2768 ast_debug(1, "%s paused, can't receive call\n", tmp->interface);
2770 ast_cdr_busy(qe->chan->cdr);
2771 tmp->stillgoing = 0;
2774 if (use_weight && compare_weight(qe->parent,tmp->member)) {
2775 ast_debug(1, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
2777 ast_cdr_busy(qe->chan->cdr);
2778 tmp->stillgoing = 0;
2783 ast_copy_string(tech, tmp->interface, sizeof(tech));
2784 if ((location = strchr(tech, '/')))
2789 /* Request the peer */
2790 tmp->chan = ast_request(tech, qe->chan->nativeformats, qe->chan, location, &status);
2791 if (!tmp->chan) { /* If we can't, just go on to the next call */
2793 ast_cdr_busy(qe->chan->cdr);
2794 tmp->stillgoing = 0;
2796 ao2_lock(qe->parent);
2797 update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member));
2798 qe->parent->rrpos++;
2800 ao2_unlock(qe->parent);
2806 ast_channel_lock(tmp->chan);
2807 while (ast_channel_trylock(qe->chan)) {
2808 CHANNEL_DEADLOCK_AVOIDANCE(tmp->chan);
2811 if (qe->cancel_answered_elsewhere) {
2812 ast_set_flag(tmp->chan, AST_FLAG_ANSWERED_ELSEWHERE);
2814 tmp->chan->appl = "AppQueue";
2815 tmp->chan->data = "(Outgoing Line)";
2816 memset(&tmp->chan->whentohangup, 0, sizeof(tmp->chan->whentohangup));
2818 /* If the new channel has no callerid, try to guess what it should be */
2819 if (ast_strlen_zero(tmp->chan->cid.cid_num)) {
2820 if (!ast_strlen_zero(qe->chan->connected.id.number)) {
2821 ast_set_callerid(tmp->chan, qe->chan->connected.id.number, qe->chan->connected.id.name, qe->chan->connected.ani);
2822 tmp->chan->cid.cid_pres = qe->chan->connected.id.number_presentation;
2823 } else if (!ast_strlen_zero(qe->chan->cid.cid_dnid)) {
2824 ast_set_callerid(tmp->chan, qe->chan->cid.cid_dnid, NULL, NULL);
2825 } else if (!ast_strlen_zero(S_OR(qe->chan->macroexten, qe->chan->exten))) {
2826 ast_set_callerid(tmp->chan, S_OR(qe->chan->macroexten, qe->chan->exten), NULL, NULL);
2828 tmp->update_connectedline = 0;
2831 if (tmp->chan->cid.cid_rdnis)
2832 ast_free(tmp->chan->cid.cid_rdnis);
2833 tmp->chan->cid.cid_rdnis = ast_strdup(qe->chan->cid.cid_rdnis);
2834 ast_party_redirecting_copy(&tmp->chan->redirecting, &qe->chan->redirecting);
2836 tmp->chan->cid.cid_tns = qe->chan->cid.cid_tns;
2838 ast_connected_line_copy_from_caller(&tmp->chan->connected, &qe->chan->cid);
2840 /* Inherit specially named variables from parent channel */
2841 ast_channel_inherit_variables(qe->chan, tmp->chan);
2842 ast_channel_datastore_inherit(qe->chan, tmp->chan);
2844 /* Presense of ADSI CPE on outgoing channel follows ours */
2845 tmp->chan->adsicpe = qe->chan->adsicpe;
2847 /* Inherit context and extension */
2848 macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT");
2849 ast_string_field_set(tmp->chan, dialcontext, ast_strlen_zero(macrocontext) ? qe->chan->context : macrocontext);
2850 macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN");
2851 if (!ast_strlen_zero(macroexten))
2852 ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten));
2854 ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten));
2855 if (ast_cdr_isset_unanswered()) {
2856 /* they want to see the unanswered dial attempts! */
2857 /* set up the CDR fields on all the CDRs to give sensical information */
2858 ast_cdr_setdestchan(tmp->chan->cdr, tmp->chan->name);
2859 strcpy(tmp->chan->cdr->clid, qe->chan->cdr->clid);
2860 strcpy(tmp->chan->cdr->channel, qe->chan->cdr->channel);
2861 strcpy(tmp->chan->cdr->src, qe->chan->cdr->src);
2862 strcpy(tmp->chan->cdr->dst, qe->chan->exten);
2863 strcpy(tmp->chan->cdr->dcontext, qe->chan->context);
2864 strcpy(tmp->chan->cdr->lastapp, qe->chan->cdr->lastapp);
2865 strcpy(tmp->chan->cdr->lastdata, qe->chan->cdr->lastdata);
2866 tmp->chan->cdr->amaflags = qe->chan->cdr->amaflags;
2867 strcpy(tmp->chan->cdr->accountcode, qe->chan->cdr->accountcode);
2868 strcpy(tmp->chan->cdr->userfield, qe->chan->cdr->userfield);
2871 /* Place the call, but don't wait on the answer */
2872 if ((res = ast_call(tmp->chan, location, 0))) {
2873 /* Again, keep going even if there's an error */
2874 ast_debug(1, "ast call on peer returned %d\n", res);
2875 ast_verb(3, "Couldn't call %s\n", tmp->interface);
2876 ast_channel_unlock(tmp->chan);
2877 ast_channel_unlock(qe->chan);
2880 update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member));
2882 } else if (qe->parent->eventwhencalled) {
2885 manager_event(EVENT_FLAG_AGENT, "AgentCalled",
2887 "AgentCalled: %s\r\n"
2889 "ChannelCalling: %s\r\n"
2890 "DestinationChannel: %s\r\n"
2891 "CallerIDNum: %s\r\n"
2892 "CallerIDName: %s\r\n"
2898 qe->parent->name, tmp->interface, tmp->member->membername, qe->chan->name, tmp->chan->name,
2899 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
2900 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
2901 qe->chan->context, qe->chan->exten, qe->chan->priority, qe->chan->uniqueid,
2902 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
2903 ast_verb(3, "Called %s\n", tmp->interface);
2905 ast_channel_unlock(tmp->chan);
2906 ast_channel_unlock(qe->chan);
2908 update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member));
2912 /*! \brief find the entry with the best metric, or NULL */
2913 static struct callattempt *find_best(struct callattempt *outgoing)
2915 struct callattempt *best = NULL, *cur;
2917 for (cur = outgoing; cur; cur = cur->q_next) {
2918 if (cur->stillgoing && /* Not already done */
2919 !cur->chan && /* Isn't already going */
2920 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */
2929 * \brief Place a call to a queue member.
2931 * Once metrics have been calculated for each member, this function is used
2932 * to place a call to the appropriate member (or members). The low-level
2933 * channel-handling and error detection is handled in ring_entry
2935 * \retval 1 if a member was called successfully
2936 * \retval 0 otherwise
2938 static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
2943 struct callattempt *best = find_best(outgoing);