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 if ((sscanf(val, "%10d", &q->penaltymemberslimit) != 1)) {
1759 q->penaltymemberslimit = 0;
1761 } else if (!strcasecmp(param, "autofill")) {
1762 q->autofill = ast_true(val);
1763 } else if (!strcasecmp(param, "monitor-type")) {
1764 if (!strcasecmp(val, "mixmonitor"))
1766 } else if (!strcasecmp(param, "autopause")) {
1767 q->autopause = ast_true(val);
1768 } else if (!strcasecmp(param, "maxlen")) {
1769 q->maxlen = atoi(val);
1772 } else if (!strcasecmp(param, "servicelevel")) {
1773 q->servicelevel= atoi(val);
1774 } else if (!strcasecmp(param, "strategy")) {
1777 /* We are a static queue and already have set this, no need to do it again */
1781 strategy = strat2int(val);
1783 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
1785 q->strategy = QUEUE_STRATEGY_RINGALL;
1787 if (strategy == q->strategy) {
1790 if (strategy == QUEUE_STRATEGY_LINEAR) {
1791 ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n");
1794 q->strategy = strategy;
1795 } else if (!strcasecmp(param, "joinempty")) {
1796 parse_empty_options(val, &q->joinempty, 1);
1797 } else if (!strcasecmp(param, "leavewhenempty")) {
1798 parse_empty_options(val, &q->leavewhenempty, 0);
1799 } else if (!strcasecmp(param, "eventmemberstatus")) {
1800 q->maskmemberstatus = !ast_true(val);
1801 } else if (!strcasecmp(param, "eventwhencalled")) {
1802 if (!strcasecmp(val, "vars")) {
1803 q->eventwhencalled = QUEUE_EVENT_VARIABLES;
1805 q->eventwhencalled = ast_true(val) ? 1 : 0;
1807 } else if (!strcasecmp(param, "reportholdtime")) {
1808 q->reportholdtime = ast_true(val);
1809 } else if (!strcasecmp(param, "memberdelay")) {
1810 q->memberdelay = atoi(val);
1811 } else if (!strcasecmp(param, "weight")) {
1812 q->weight = atoi(val);
1813 } else if (!strcasecmp(param, "timeoutrestart")) {
1814 q->timeoutrestart = ast_true(val);
1815 } else if (!strcasecmp(param, "defaultrule")) {
1816 ast_string_field_set(q, defaultrule, val);
1817 } else if (!strcasecmp(param, "timeoutpriority")) {
1818 if (!strcasecmp(val, "conf")) {
1819 q->timeoutpriority = TIMEOUT_PRIORITY_CONF;
1821 q->timeoutpriority = TIMEOUT_PRIORITY_APP;
1823 } else if (failunknown) {
1825 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
1826 q->name, param, linenum);
1828 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
1834 * \brief Find rt member record to update otherwise create one.
1836 * Search for member in queue, if found update penalty/paused state,
1837 * if no memeber exists create one flag it as a RT member and add to queue member list.
1839 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)
1842 struct ao2_iterator mem_iter;
1848 penalty = atoi(penalty_str);
1854 paused = atoi(paused_str);
1859 /* Find member by realtime uniqueid and update */
1860 mem_iter = ao2_iterator_init(q->members, 0);
1861 while ((m = ao2_iterator_next(&mem_iter))) {
1862 if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) {
1863 m->dead = 0; /* Do not delete this one. */
1864 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
1867 if (strcasecmp(state_interface, m->state_interface)) {
1868 ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
1870 m->penalty = penalty;
1877 ao2_iterator_destroy(&mem_iter);
1879 /* Create a new member */
1881 if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) {
1884 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
1885 ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", "");
1886 ao2_link(q->members, m);
1894 /*! \brief Iterate through queue's member list and delete them */
1895 static void free_members(struct call_queue *q, int all)
1897 /* Free non-dynamic members */
1899 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
1901 while ((cur = ao2_iterator_next(&mem_iter))) {
1902 if (all || !cur->dynamic) {
1903 ao2_unlink(q->members, cur);
1908 ao2_iterator_destroy(&mem_iter);
1911 /*! \brief Free queue's member list then its string fields */
1912 static void destroy_queue(void *obj)
1914 struct call_queue *q = obj;
1918 ast_string_field_free_memory(q);
1919 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
1920 if (q->sound_periodicannounce[i])
1921 free(q->sound_periodicannounce[i]);
1923 ao2_ref(q->members, -1);
1926 static struct call_queue *alloc_queue(const char *queuename)
1928 struct call_queue *q;
1930 if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) {
1931 if (ast_string_field_init(q, 64)) {
1932 queue_t_unref(q, "String field allocation failed");
1935 ast_string_field_set(q, name, queuename);
1941 * \brief Reload a single queue via realtime.
1943 * Check for statically defined queue first, check if deleted RT queue,
1944 * check for new RT queue, if queue vars are not defined init them with defaults.
1945 * reload RT queue vars, set RT queue members dead and reload them, return finished queue.
1946 * \retval the queue,
1947 * \retval NULL if it doesn't exist.
1948 * \note Should be called with the "queues" container locked.
1950 static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
1952 struct ast_variable *v;
1953 struct call_queue *q, tmpq = {
1957 struct ao2_iterator mem_iter;
1958 char *interface = NULL;
1959 const char *tmp_name;
1961 char tmpbuf[64]; /* Must be longer than the longest queue param name. */
1963 /* Static queues override realtime. */
1964 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Check if static queue exists"))) {
1969 queue_t_unref(q, "Queue is dead; can't return it");
1972 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
1977 } else if (!member_config)
1978 /* Not found in the list, and it's not realtime ... */
1981 /* Check if queue is defined in realtime. */
1983 /* Delete queue from in-core list if it has been deleted in realtime. */
1985 /*! \note Hmm, can't seem to distinguish a DB failure from a not
1986 found condition... So we might delete an in-core queue
1987 in case of DB failure. */
1988 ast_debug(1, "Queue %s not found in realtime.\n", queuename);
1991 /* Delete if unused (else will be deleted when last caller leaves). */
1992 queues_t_unlink(queues, q, "Unused; removing from container");
1994 queue_t_unref(q, "Queue is dead; can't return it");
1999 /* Create a new queue if an in-core entry does not exist yet. */
2001 struct ast_variable *tmpvar = NULL;
2002 if (!(q = alloc_queue(queuename)))
2008 /*Before we initialize the queue, we need to set the strategy, so that linear strategy
2009 * will allocate the members properly
2011 for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) {
2012 if (!strcasecmp(tmpvar->name, "strategy")) {
2013 q->strategy = strat2int(tmpvar->value);
2014 if (q->strategy < 0) {
2015 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
2016 tmpvar->value, q->name);
2017 q->strategy = QUEUE_STRATEGY_RINGALL;
2022 /* We traversed all variables and didn't find a strategy */
2024 q->strategy = QUEUE_STRATEGY_RINGALL;
2025 queues_t_link(queues, q, "Add queue to container");
2027 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
2029 memset(tmpbuf, 0, sizeof(tmpbuf));
2030 for (v = queue_vars; v; v = v->next) {
2031 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
2032 if ((tmp = strchr(v->name, '_'))) {
2033 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
2036 while ((tmp = strchr(tmp, '_')))
2041 if (!ast_strlen_zero(v->value)) {
2042 /* Don't want to try to set the option if the value is empty */
2043 queue_set_param(q, tmp_name, v->value, -1, 0);
2047 /* Temporarily set realtime members dead so we can detect deleted ones.
2048 * Also set the membercount correctly for realtime*/
2049 mem_iter = ao2_iterator_init(q->members, 0);
2050 while ((m = ao2_iterator_next(&mem_iter))) {
2056 ao2_iterator_destroy(&mem_iter);
2058 while ((interface = ast_category_browse(member_config, interface))) {
2059 rt_handle_member_record(q, interface,
2060 ast_variable_retrieve(member_config, interface, "uniqueid"),
2061 S_OR(ast_variable_retrieve(member_config, interface, "membername"),interface),
2062 ast_variable_retrieve(member_config, interface, "penalty"),
2063 ast_variable_retrieve(member_config, interface, "paused"),
2064 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface));
2067 /* Delete all realtime members that have been deleted in DB. */
2068 mem_iter = ao2_iterator_init(q->members, 0);
2069 while ((m = ao2_iterator_next(&mem_iter))) {
2071 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
2072 ao2_unlink(q->members, m);
2077 ao2_iterator_destroy(&mem_iter);
2084 static struct call_queue *load_realtime_queue(const char *queuename)
2086 struct ast_variable *queue_vars;
2087 struct ast_config *member_config = NULL;
2088 struct call_queue *q = NULL, tmpq = {
2091 int prev_weight = 0;
2093 /* Find the queue in the in-core list first. */
2094 q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Look for queue in memory first");
2096 if (!q || q->realtime) {
2097 /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all
2098 queue operations while waiting for the DB.
2100 This will be two separate database transactions, so we might
2101 see queue parameters as they were before another process
2102 changed the queue and member list as it was after the change.
2103 Thus we might see an empty member list when a queue is
2104 deleted. In practise, this is unlikely to cause a problem. */
2106 queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL);
2108 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL);
2109 if (!member_config) {
2110 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
2111 ast_variables_destroy(queue_vars);
2116 prev_weight = q->weight ? 1 : 0;
2121 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
2122 if (member_config) {
2123 ast_config_destroy(member_config);
2126 ast_variables_destroy(queue_vars);
2128 /* update the use_weight value if the queue's has gained or lost a weight */
2130 if (!q->weight && prev_weight) {
2131 ast_atomic_fetchadd_int(&use_weight, -1);
2133 if (q->weight && !prev_weight) {
2134 ast_atomic_fetchadd_int(&use_weight, +1);
2137 /* Other cases will end up with the proper value for use_weight */
2141 update_realtime_members(q);
2146 static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
2150 if (ast_strlen_zero(mem->rt_uniqueid))
2153 if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) > 0)
2160 static void update_realtime_members(struct call_queue *q)
2162 struct ast_config *member_config = NULL;
2164 char *interface = NULL;
2165 struct ao2_iterator mem_iter;
2167 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , SENTINEL))) {
2168 /*This queue doesn't have realtime members*/
2169 ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name);
2176 /* Temporarily set realtime members dead so we can detect deleted ones.*/
2177 mem_iter = ao2_iterator_init(q->members, 0);
2178 while ((m = ao2_iterator_next(&mem_iter))) {
2183 ao2_iterator_destroy(&mem_iter);
2185 while ((interface = ast_category_browse(member_config, interface))) {
2186 rt_handle_member_record(q, interface,
2187 ast_variable_retrieve(member_config, interface, "uniqueid"),
2188 S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
2189 ast_variable_retrieve(member_config, interface, "penalty"),
2190 ast_variable_retrieve(member_config, interface, "paused"),
2191 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface));
2194 /* Delete all realtime members that have been deleted in DB. */
2195 mem_iter = ao2_iterator_init(q->members, 0);
2196 while ((m = ao2_iterator_next(&mem_iter))) {
2198 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
2199 ao2_unlink(q->members, m);
2204 ao2_iterator_destroy(&mem_iter);
2207 ast_config_destroy(member_config);
2210 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
2212 struct call_queue *q;
2213 struct queue_ent *cur, *prev = NULL;
2218 if (!(q = load_realtime_queue(queuename)))
2224 /* This is our one */
2227 if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, q->joinempty))) {
2228 *reason = QUEUE_JOINEMPTY;
2234 if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen))
2235 *reason = QUEUE_FULL;
2236 else if (*reason == QUEUE_UNKNOWN) {
2237 /* There's space for us, put us at the right position inside
2239 * Take into account the priority of the calling user */
2244 /* We have higher priority than the current user, enter
2245 * before him, after all the other users with priority
2246 * higher or equal to our priority. */
2247 if ((!inserted) && (qe->prio > cur->prio)) {
2248 insert_entry(q, prev, qe, &pos);
2251 /* <= is necessary for the position comparison because it may not be possible to enter
2252 * at our desired position since higher-priority callers may have taken the position we want
2254 if (!inserted && (qe->prio <= cur->prio) && position && (position <= pos + 1)) {
2255 insert_entry(q, prev, qe, &pos);
2256 /*pos is incremented inside insert_entry, so don't need to add 1 here*/
2257 if (position < pos) {
2258 ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos);
2266 /* No luck, join at the end of the queue */
2268 insert_entry(q, prev, qe, &pos);
2269 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
2270 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
2271 ast_copy_string(qe->context, q->context, sizeof(qe->context));
2274 ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Join",
2275 "Channel: %s\r\nCallerIDNum: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
2277 S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */
2278 S_OR(qe->chan->cid.cid_name, "unknown"),
2279 q->name, qe->pos, q->count, qe->chan->uniqueid );
2280 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
2288 static int play_file(struct ast_channel *chan, const char *filename)
2292 if (ast_strlen_zero(filename)) {
2296 ast_stopstream(chan);
2298 res = ast_streamfile(chan, filename, chan->language);
2300 res = ast_waitstream(chan, AST_DIGIT_ANY);
2302 ast_stopstream(chan);
2308 * \brief Check for valid exit from queue via goto
2309 * \retval 0 if failure
2310 * \retval 1 if successful
2312 static int valid_exit(struct queue_ent *qe, char digit)
2314 int digitlen = strlen(qe->digits);
2316 /* Prevent possible buffer overflow */
2317 if (digitlen < sizeof(qe->digits) - 2) {
2318 qe->digits[digitlen] = digit;
2319 qe->digits[digitlen + 1] = '\0';
2321 qe->digits[0] = '\0';
2325 /* If there's no context to goto, short-circuit */
2326 if (ast_strlen_zero(qe->context))
2329 /* If the extension is bad, then reset the digits to blank */
2330 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) {
2331 qe->digits[0] = '\0';
2335 /* We have an exact match */
2336 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
2337 qe->valid_digits = 1;
2338 /* Return 1 on a successful goto */
2345 static int say_position(struct queue_ent *qe, int ringing)
2347 int res = 0, avgholdmins, avgholdsecs, announceposition = 0;
2351 /* Let minannouncefrequency seconds pass between the start of each position announcement */
2353 if ((now - qe->last_pos) < qe->parent->minannouncefrequency)
2356 /* If either our position has changed, or we are over the freq timer, say position */
2357 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency))
2361 ast_indicate(qe->chan,-1);
2363 ast_moh_stop(qe->chan);
2366 if (qe->parent->announceposition == ANNOUNCEPOSITION_YES ||
2367 qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN ||
2368 (qe->parent->announceposition == ANNOUNCEPOSITION_LIMIT &&
2369 qe->pos <= qe->parent->announcepositionlimit))
2370 announceposition = 1;
2373 if (announceposition == 1) {
2374 /* Say we're next, if we are */
2376 res = play_file(qe->chan, qe->parent->sound_next);
2382 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){
2384 res = play_file(qe->chan, qe->parent->queue_quantity1);
2387 res = ast_say_number(qe->chan, qe->parent->announcepositionlimit, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */
2392 res = play_file(qe->chan, qe->parent->sound_thereare);
2395 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */
2399 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){
2401 res = play_file(qe->chan, qe->parent->queue_quantity2);
2405 res = play_file(qe->chan, qe->parent->sound_calls);
2411 /* Round hold time to nearest minute */
2412 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
2414 /* If they have specified a rounding then round the seconds as well */
2415 if (qe->parent->roundingseconds) {
2416 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
2417 avgholdsecs *= qe->parent->roundingseconds;
2422 ast_verb(3, "Hold time for %s is %d minute(s) %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
2424 /* If the hold time is >1 min, if it's enabled, and if it's not
2425 supposed to be only once and we have already said it, say it */
2426 if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime &&
2427 ((qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE && !qe->last_pos) ||
2428 !(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE))) {
2429 res = play_file(qe->chan, qe->parent->sound_holdtime);
2433 if (avgholdmins >= 1) {
2434 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL);
2438 if (avgholdmins == 1) {
2439 res = play_file(qe->chan, qe->parent->sound_minute);
2443 res = play_file(qe->chan, qe->parent->sound_minutes);
2448 if (avgholdsecs >= 1) {
2449 res = ast_say_number(qe->chan, avgholdmins > 1 ? avgholdsecs : avgholdmins * 60 + avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL);
2453 res = play_file(qe->chan, qe->parent->sound_seconds);
2457 } else if (qe->parent->announceholdtime && !qe->parent->announceposition) {
2462 if (qe->parent->announceposition) {
2463 ast_verb(3, "Told %s in %s their queue position (which was %d)\n",
2464 qe->chan->name, qe->parent->name, qe->pos);
2467 res = play_file(qe->chan, qe->parent->sound_thanks);
2471 if ((res > 0 && !valid_exit(qe, res)))
2474 /* Set our last_pos indicators */
2476 qe->last_pos_said = qe->pos;
2478 /* Don't restart music on hold if we're about to exit the caller from the queue */
2481 ast_indicate(qe->chan, AST_CONTROL_RINGING);
2483 ast_moh_start(qe->chan, qe->moh, NULL);
2489 static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
2493 /* Calculate holdtime using an exponential average */
2494 /* Thanks to SRT for this contribution */
2495 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
2497 ao2_lock(qe->parent);
2498 oldvalue = qe->parent->holdtime;
2499 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
2500 ao2_unlock(qe->parent);
2503 /*! \brief Caller leaving queue.
2505 * Search the queue to find the leaving client, if found remove from queue
2506 * create manager event, move others up the queue.
2508 static void leave_queue(struct queue_ent *qe)
2510 struct call_queue *q;
2511 struct queue_ent *current, *prev = NULL;
2512 struct penalty_rule *pr_iter;
2515 if (!(q = qe->parent))
2517 queue_t_ref(q, "Copy queue pointer from queue entry");
2521 for (current = q->head; current; current = current->next) {
2522 if (current == qe) {
2526 /* Take us out of the queue */
2527 ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Leave",
2528 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nPosition: %d\r\nUniqueid: %s\r\n",
2529 qe->chan->name, q->name, q->count, qe->pos, qe->chan->uniqueid);
2530 ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
2531 /* Take us out of the queue */
2533 prev->next = current->next;
2535 q->head = current->next;
2536 /* Free penalty rules */
2537 while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list)))
2539 snprintf(posstr, sizeof(posstr), "%d", qe->pos);
2540 pbx_builtin_setvar_helper(qe->chan, "QUEUEPOSITION", posstr);
2542 /* Renumber the people after us in the queue based on a new count */
2543 current->pos = ++pos;
2549 /*If the queue is a realtime queue, check to see if it's still defined in real time*/
2551 struct ast_variable *var;
2552 if (!(var = ast_load_realtime("queues", "name", q->name, SENTINEL))) {
2555 ast_variables_destroy(var);
2560 /* It's dead and nobody is in it, so kill it */
2561 queues_t_unlink(queues, q, "Queue is now dead; remove it from the container");
2563 /* unref the explicit ref earlier in the function */
2564 queue_t_unref(q, "Expire copied reference");
2567 /*! \brief Hang up a list of outgoing calls */
2568 static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere)
2570 struct callattempt *oo;
2573 /* If someone else answered the call we should indicate this in the CANCEL */
2574 /* Hangup any existing lines we have open */
2575 if (outgoing->chan && (outgoing->chan != exception || cancel_answered_elsewhere)) {
2576 if (exception || cancel_answered_elsewhere)
2577 ast_set_flag(outgoing->chan, AST_FLAG_ANSWERED_ELSEWHERE);
2578 ast_hangup(outgoing->chan);
2581 outgoing = outgoing->q_next;
2583 ao2_ref(oo->member, -1);
2589 * \brief Get the number of members available to accept a call.
2591 * \note The queue passed in should be locked prior to this function call
2593 * \param[in] q The queue for which we are couting the number of available members
2594 * \return Return the number of available members in queue q
2596 static int num_available_members(struct call_queue *q)
2600 struct ao2_iterator mem_iter;
2602 mem_iter = ao2_iterator_init(q->members, 0);
2603 while ((mem = ao2_iterator_next(&mem_iter))) {
2604 switch (mem->status) {
2605 case AST_DEVICE_INUSE:
2608 /* else fall through */
2609 case AST_DEVICE_NOT_INUSE:
2610 case AST_DEVICE_UNKNOWN:
2618 /* If autofill is not enabled or if the queue's strategy is ringall, then
2619 * we really don't care about the number of available members so much as we
2620 * do that there is at least one available.
2622 * In fact, we purposely will return from this function stating that only
2623 * one member is available if either of those conditions hold. That way,
2624 * functions which determine what action to take based on the number of available
2625 * members will operate properly. The reasoning is that even if multiple
2626 * members are available, only the head caller can actually be serviced.
2628 if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) {
2632 ao2_iterator_destroy(&mem_iter);
2637 /* traverse all defined queues which have calls waiting and contain this member
2638 return 0 if no other queue has precedence (higher weight) or 1 if found */
2639 static int compare_weight(struct call_queue *rq, struct member *member)
2641 struct call_queue *q;
2644 struct ao2_iterator queue_iter;
2646 /* q's lock and rq's lock already set by try_calling()
2647 * to solve deadlock */
2648 queue_iter = ao2_iterator_init(queues, 0);
2649 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
2650 if (q == rq) { /* don't check myself, could deadlock */
2651 queue_t_unref(q, "Done with iterator");
2655 if (q->count && q->members) {
2656 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
2657 ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
2658 if (q->weight > rq->weight && q->count >= num_available_members(q)) {
2659 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);
2666 queue_t_unref(q, "Done with iterator");
2671 ao2_iterator_destroy(&queue_iter);
2675 /*! \brief common hangup actions */
2676 static void do_hang(struct callattempt *o)
2679 ast_hangup(o->chan);
2683 /*! \brief convert "\n" to "\nVariable: " ready for manager to use */
2684 static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
2686 struct ast_str *buf = ast_str_thread_get(&ast_str_thread_global_buf, len + 1);
2689 if (pbx_builtin_serialize_variables(chan, &buf)) {
2692 /* convert "\n" to "\nVariable: " */
2693 strcpy(vars, "Variable: ");
2694 tmp = ast_str_buffer(buf);
2696 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) {
2699 if (tmp[i + 1] == '\0')
2701 if (tmp[i] == '\n') {
2705 ast_copy_string(&(vars[j]), "Variable: ", len - j);
2715 /* there are no channel variables; leave it blank */
2722 * \brief Part 2 of ring_one
2724 * Does error checking before attempting to request a channel and call a member.
2725 * This function is only called from ring_one().
2726 * Failure can occur if:
2729 * - Wrapup time not expired
2730 * - Priority by another queue
2732 * \retval 1 on success to reach a free agent
2733 * \retval 0 on failure to get agent.
2735 static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
2741 const char *macrocontext, *macroexten;
2743 /* on entry here, we know that tmp->chan == NULL */
2744 if ((tmp->lastqueue && tmp->lastqueue->wrapuptime && (time(NULL) - tmp->lastcall < tmp->lastqueue->wrapuptime)) ||
2745 (!tmp->lastqueue && qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime))) {
2746 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
2747 (tmp->lastqueue ? tmp->lastqueue->name : qe->parent->name), tmp->interface);
2749 ast_cdr_busy(qe->chan->cdr);
2750 tmp->stillgoing = 0;
2755 if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
2756 ast_debug(1, "%s in use, can't receive call\n", tmp->interface);
2758 ast_cdr_busy(qe->chan->cdr);
2759 tmp->stillgoing = 0;
2763 if (tmp->member->paused) {
2764 ast_debug(1, "%s paused, can't receive call\n", tmp->interface);
2766 ast_cdr_busy(qe->chan->cdr);
2767 tmp->stillgoing = 0;
2770 if (use_weight && compare_weight(qe->parent,tmp->member)) {
2771 ast_debug(1, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
2773 ast_cdr_busy(qe->chan->cdr);
2774 tmp->stillgoing = 0;
2779 ast_copy_string(tech, tmp->interface, sizeof(tech));
2780 if ((location = strchr(tech, '/')))
2785 /* Request the peer */
2786 tmp->chan = ast_request(tech, qe->chan->nativeformats, qe->chan, location, &status);
2787 if (!tmp->chan) { /* If we can't, just go on to the next call */
2789 ast_cdr_busy(qe->chan->cdr);
2790 tmp->stillgoing = 0;
2792 ao2_lock(qe->parent);
2793 update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member));
2794 qe->parent->rrpos++;
2796 ao2_unlock(qe->parent);
2802 ast_channel_lock(tmp->chan);
2803 while (ast_channel_trylock(qe->chan)) {
2804 CHANNEL_DEADLOCK_AVOIDANCE(tmp->chan);
2807 if (qe->cancel_answered_elsewhere) {
2808 ast_set_flag(tmp->chan, AST_FLAG_ANSWERED_ELSEWHERE);
2810 tmp->chan->appl = "AppQueue";
2811 tmp->chan->data = "(Outgoing Line)";
2812 memset(&tmp->chan->whentohangup, 0, sizeof(tmp->chan->whentohangup));
2814 /* If the new channel has no callerid, try to guess what it should be */
2815 if (ast_strlen_zero(tmp->chan->cid.cid_num)) {
2816 if (!ast_strlen_zero(qe->chan->connected.id.number)) {
2817 ast_set_callerid(tmp->chan, qe->chan->connected.id.number, qe->chan->connected.id.name, qe->chan->connected.ani);
2818 tmp->chan->cid.cid_pres = qe->chan->connected.id.number_presentation;
2819 } else if (!ast_strlen_zero(qe->chan->cid.cid_dnid)) {
2820 ast_set_callerid(tmp->chan, qe->chan->cid.cid_dnid, NULL, NULL);
2821 } else if (!ast_strlen_zero(S_OR(qe->chan->macroexten, qe->chan->exten))) {
2822 ast_set_callerid(tmp->chan, S_OR(qe->chan->macroexten, qe->chan->exten), NULL, NULL);
2824 tmp->update_connectedline = 0;
2827 if (tmp->chan->cid.cid_rdnis)
2828 ast_free(tmp->chan->cid.cid_rdnis);
2829 tmp->chan->cid.cid_rdnis = ast_strdup(qe->chan->cid.cid_rdnis);
2830 ast_party_redirecting_copy(&tmp->chan->redirecting, &qe->chan->redirecting);
2832 tmp->chan->cid.cid_tns = qe->chan->cid.cid_tns;
2834 ast_connected_line_copy_from_caller(&tmp->chan->connected, &qe->chan->cid);
2836 /* Inherit specially named variables from parent channel */
2837 ast_channel_inherit_variables(qe->chan, tmp->chan);
2838 ast_channel_datastore_inherit(qe->chan, tmp->chan);
2840 /* Presense of ADSI CPE on outgoing channel follows ours */
2841 tmp->chan->adsicpe = qe->chan->adsicpe;
2843 /* Inherit context and extension */
2844 macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT");
2845 ast_string_field_set(tmp->chan, dialcontext, ast_strlen_zero(macrocontext) ? qe->chan->context : macrocontext);
2846 macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN");
2847 if (!ast_strlen_zero(macroexten))
2848 ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten));
2850 ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten));
2851 if (ast_cdr_isset_unanswered()) {
2852 /* they want to see the unanswered dial attempts! */
2853 /* set up the CDR fields on all the CDRs to give sensical information */
2854 ast_cdr_setdestchan(tmp->chan->cdr, tmp->chan->name);
2855 strcpy(tmp->chan->cdr->clid, qe->chan->cdr->clid);
2856 strcpy(tmp->chan->cdr->channel, qe->chan->cdr->channel);
2857 strcpy(tmp->chan->cdr->src, qe->chan->cdr->src);
2858 strcpy(tmp->chan->cdr->dst, qe->chan->exten);
2859 strcpy(tmp->chan->cdr->dcontext, qe->chan->context);
2860 strcpy(tmp->chan->cdr->lastapp, qe->chan->cdr->lastapp);
2861 strcpy(tmp->chan->cdr->lastdata, qe->chan->cdr->lastdata);
2862 tmp->chan->cdr->amaflags = qe->chan->cdr->amaflags;
2863 strcpy(tmp->chan->cdr->accountcode, qe->chan->cdr->accountcode);
2864 strcpy(tmp->chan->cdr->userfield, qe->chan->cdr->userfield);
2867 /* Place the call, but don't wait on the answer */
2868 if ((res = ast_call(tmp->chan, location, 0))) {
2869 /* Again, keep going even if there's an error */
2870 ast_debug(1, "ast call on peer returned %d\n", res);
2871 ast_verb(3, "Couldn't call %s\n", tmp->interface);
2872 ast_channel_unlock(tmp->chan);
2873 ast_channel_unlock(qe->chan);
2876 update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member));
2878 } else if (qe->parent->eventwhencalled) {
2881 manager_event(EVENT_FLAG_AGENT, "AgentCalled",
2883 "AgentCalled: %s\r\n"
2885 "ChannelCalling: %s\r\n"
2886 "DestinationChannel: %s\r\n"
2887 "CallerIDNum: %s\r\n"
2888 "CallerIDName: %s\r\n"
2894 qe->parent->name, tmp->interface, tmp->member->membername, qe->chan->name, tmp->chan->name,
2895 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
2896 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
2897 qe->chan->context, qe->chan->exten, qe->chan->priority, qe->chan->uniqueid,
2898 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
2899 ast_verb(3, "Called %s\n", tmp->interface);
2901 ast_channel_unlock(tmp->chan);
2902 ast_channel_unlock(qe->chan);
2904 update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member));
2908 /*! \brief find the entry with the best metric, or NULL */
2909 static struct callattempt *find_best(struct callattempt *outgoing)
2911 struct callattempt *best = NULL, *cur;
2913 for (cur = outgoing; cur; cur = cur->q_next) {
2914 if (cur->stillgoing && /* Not already done */
2915 !cur->chan && /* Isn't already going */
2916 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */
2925 * \brief Place a call to a queue member.
2927 * Once metrics have been calculated for each member, this function is used
2928 * to place a call to the appropriate member (or members). The low-level
2929 * channel-handling and error detection is handled in ring_entry
2931 * \retval 1 if a member was called successfully
2932 * \retval 0 otherwise
2934 static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
2939 struct callattempt *best = find_best(outgoing);
2941 ast_debug(1, "Nobody left to try ringing in queue\n");
2944 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
2945 struct callattempt *cur;
2946 /* Ring everyone who shares this best metric (for ringall) */
2947 for (cur = outgoing; cur; cur = cur->q_next) {
2948 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
2949 ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
2950 ret |= ring_entry(qe, cur, busies);
2954 /* Ring just the best channel */
2955 ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric);
2956 ret = ring_entry(qe, best, busies);
2959 /* If we have timed out, break out */
2960 if (qe->expire && (time(NULL) >= qe->expire)) {
2961 ast_debug(1, "Queue timed out while ringing members.\n");
2970 /*! \brief Search for best metric and add to Round Robbin queue */
2971 static int store_next_rr(struct queue_ent *qe, struct callattempt *outgoing)
2973 struct callattempt *best = find_best(outgoing);
2976 /* Ring just the best channel */
2977 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
2978 qe->parent->rrpos = best->metric % 1000;
2980 /* Just increment rrpos */
2981 if (qe->parent->wrapped) {
2982 /* No more channels, start over */
2983 qe->parent->rrpos = 0;
2985 /* Prioritize next entry */
2986 qe->parent->rrpos++;
2989 qe->parent->wrapped = 0;
2994 /*! \brief Search for best metric and add to Linear queue */
2995 static int store_next_lin(struct queue_ent *qe, struct callattempt *outgoing)
2997 struct callattempt *best = find_best(outgoing);
3000 /* Ring just the best channel */
3001 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
3002 qe->linpos = best->metric % 1000;
3004 /* Just increment rrpos */
3005 if (qe->linwrapped) {
3006 /* No more channels, start over */
3009 /* Prioritize next entry */
3018 /*! \brief Playback announcement to queued members if peroid has elapsed */
3019 static int say_periodic_announcement(struct queue_ent *qe, int ringing)
3024 /* Get the current time */
3027 /* Check to see if it is time to announce */
3028 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
3031 /* Stop the music on hold so we can play our own file */
3033 ast_indicate(qe->chan,-1);
3035 ast_moh_stop(qe->chan);
3037 ast_verb(3, "Playing periodic announcement\n");
3039 if (qe->parent->randomperiodicannounce && qe->parent->numperiodicannounce) {
3040 qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce;
3041 } else if (qe->last_periodic_announce_sound >= qe->parent->numperiodicannounce ||
3042 ast_str_strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]) == 0) {
3043 qe->last_periodic_announce_sound = 0;
3046 /* play the announcement */
3047 res = play_file(qe->chan, ast_str_buffer(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]));
3049 if (res > 0 && !valid_exit(qe, res))
3052 /* Resume Music on Hold if the caller is going to stay in the queue */
3055 ast_indicate(qe->chan, AST_CONTROL_RINGING);
3057 ast_moh_start(qe->chan, qe->moh, NULL);
3060 /* update last_periodic_announce_time */
3061 if (qe->parent->relativeperiodicannounce)
3062 time(&qe->last_periodic_announce_time);
3064 qe->last_periodic_announce_time = now;
3066 /* Update the current periodic announcement to the next announcement */
3067 if (!qe->parent->randomperiodicannounce) {
3068 qe->last_periodic_announce_sound++;
3074 /*! \brief Record that a caller gave up on waiting in queue */
3075 static void record_abandoned(struct queue_ent *qe)
3077 ao2_lock(qe->parent);
3078 set_queue_variables(qe->parent, qe->chan);
3079 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
3083 "OriginalPosition: %d\r\n"
3085 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start));
3087 qe->parent->callsabandoned++;
3088 ao2_unlock(qe->parent);
3091 /*! \brief RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. */
3092 static void rna(int rnatime, struct queue_ent *qe, char *interface, char *membername, int pause)
3094 ast_verb(3, "Nobody picked up in %d ms\n", rnatime);
3095 if (qe->parent->eventwhencalled) {
3098 manager_event(EVENT_FLAG_AGENT, "AgentRingNoAnswer",
3103 "MemberName: %s\r\n"
3112 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
3114 ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
3115 if (qe->parent->autopause && pause) {
3116 if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) {
3117 ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name);
3119 ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
3125 #define AST_MAX_WATCHERS 256
3126 /*! \brief Wait for a member to answer the call
3128 * \param[in] qe the queue_ent corresponding to the caller in the queue
3129 * \param[in] outgoing the list of callattempts. Relevant ones will have their chan and stillgoing parameters non-zero
3130 * \param[in] to the amount of time (in milliseconds) to wait for a response
3131 * \param[out] digit if a user presses a digit to exit the queue, this is the digit the caller pressed
3132 * \param[in] prebusies number of busy members calculated prior to calling wait_for_answer
3133 * \param[in] caller_disconnect if the 'H' option is used when calling Queue(), this is used to detect if the caller pressed * to disconnect the call
3134 * \param[in] forwardsallowed used to detect if we should allow call forwarding, based on the 'i' option to Queue()
3136 * \todo eventually all call forward logic should be intergerated into and replaced by ast_call_forward()
3138 static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed, int update_connectedline)
3140 const char *queue = qe->parent->name;
3141 struct callattempt *o, *start = NULL, *prev = NULL;
3143 int numbusies = prebusies;
3147 struct ast_frame *f;
3148 struct callattempt *peer = NULL;
3149 struct ast_channel *winner;
3150 struct ast_channel *in = qe->chan;
3152 char membername[80] = "";
3156 struct callattempt *epollo;
3158 struct ast_party_connected_line connected_caller;
3161 ast_party_connected_line_init(&connected_caller);
3163 ast_channel_lock(qe->chan);
3164 inchan_name = ast_strdupa(qe->chan->name);
3165 ast_channel_unlock(qe->chan);
3167 starttime = (long) time(NULL);
3169 for (epollo = outgoing; epollo; epollo = epollo->q_next) {
3171 ast_poll_channel_add(in, epollo->chan);
3175 while (*to && !peer) {
3176 int numlines, retry, pos = 1;
3177 struct ast_channel *watchers[AST_MAX_WATCHERS];
3181 for (retry = 0; retry < 2; retry++) {
3183 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
3184 if (o->stillgoing) { /* Keep track of important channels */
3187 watchers[pos++] = o->chan;
3191 prev->call_next = o;
3197 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
3198 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */)
3200 /* On "ringall" strategy we only move to the next penalty level
3201 when *all* ringing phones are done in the current penalty level */
3202 ring_one(qe, outgoing, &numbusies);
3205 if (pos == 1 /* not found */) {
3206 if (numlines == (numbusies + numnochan)) {
3207 ast_debug(1, "Everyone is busy at this time\n");
3209 ast_debug(3, "No one is answering queue '%s' (%d numlines / %d busies / %d failed channels)\n", queue, numlines, numbusies, numnochan);
3215 /* Poll for events from both the incoming channel as well as any outgoing channels */
3216 winner = ast_waitfor_n(watchers, pos, to);
3218 /* Service all of the outgoing channels */
3219 for (o = start; o; o = o->call_next) {
3220 /* We go with a static buffer here instead of using ast_strdupa. Using
3221 * ast_strdupa in a loop like this one can cause a stack overflow
3223 char ochan_name[AST_CHANNEL_NAME];
3225 ast_channel_lock(o->chan);
3226 ast_copy_string(ochan_name, o->chan->name, sizeof(ochan_name));
3227 ast_channel_unlock(o->chan);
3229 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
3231 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
3232 if (update_connectedline) {
3233 if (o->connected.id.number) {
3234 if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
3235 ast_channel_update_connected_line(in, &o->connected);
3237 } else if (o->update_connectedline) {
3238 ast_channel_lock(o->chan);
3239 ast_connected_line_copy_from_caller(&connected_caller, &o->chan->cid);
3240 ast_channel_unlock(o->chan);
3241 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
3242 ast_channel_update_connected_line(in, &connected_caller);
3243 ast_party_connected_line_free(&connected_caller);
3248 } else if (o->chan && (o->chan == winner)) {
3250 ast_copy_string(on, o->member->interface, sizeof(on));
3251 ast_copy_string(membername, o->member->membername, sizeof(membername));
3253 if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) {
3254 ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, o->chan->call_forward);
3259 } else if (!ast_strlen_zero(o->chan->call_forward)) {
3260 struct ast_party_redirecting *apr = &o->chan->redirecting;
3261 struct ast_party_connected_line *apc = &o->chan->connected;
3262 struct ast_channel *original = o->chan;
3267 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
3268 if ((stuff = strchr(tmpchan, '/'))) {
3272 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
3277 ast_cel_report_event(in, AST_CEL_FORWARD, NULL, o->chan->call_forward, NULL);
3279 /* Before processing channel, go ahead and check for forwarding */
3280 ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name);
3281 /* Setup parameters */
3282 o->chan = ast_request(tech, in->nativeformats, in, stuff, &status);
3284 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
3288 ast_channel_lock(o->chan);
3289 while (ast_channel_trylock(in)) {
3290 CHANNEL_DEADLOCK_AVOIDANCE(o->chan);
3292 ast_channel_inherit_variables(in, o->chan);
3293 ast_channel_datastore_inherit(in, o->chan);
3295 ast_string_field_set(o->chan, accountcode, in->accountcode);
3296 o->chan->cdrflags = in->cdrflags;
3298 ast_channel_set_redirecting(o->chan, apr);
3300 if (o->chan->cid.cid_rdnis)
3301 ast_free(o->chan->cid.cid_rdnis);
3302 o->chan->cid.cid_rdnis = ast_strdup(S_OR(original->cid.cid_rdnis,S_OR(in->macroexten, in->exten)));
3304 o->chan->cid.cid_tns = in->cid.cid_tns;
3306 ast_party_caller_copy(&o->chan->cid, &in->cid);
3307 ast_party_connected_line_copy(&o->chan->connected, apc);
3309 ast_channel_update_redirecting(in, apr);
3310 if (in->cid.cid_rdnis) {
3311 ast_free(in->cid.cid_rdnis);
3313 in->cid.cid_rdnis = ast_strdup(o->chan->cid.cid_rdnis);
3315 update_connectedline = 1;
3317 if (ast_call(o->chan, tmpchan, 0)) {
3318 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
3319 ast_channel_unlock(o->chan);