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"
99 * \par Please read before modifying this file.
100 * There are three locks which are regularly used
101 * throughout this file, the queue list lock, the lock
102 * for each individual queue, and the interface list lock.
103 * Please be extra careful to always lock in the following order
105 * 2) individual queue lock
106 * 3) interface list lock
107 * This order has sort of "evolved" over the lifetime of this
108 * application, but it is now in place this way, so please adhere
113 <application name="Queue" language="en_US">
115 Queue a call for a call queue.
118 <parameter name="queuename" required="true" />
119 <parameter name="options">
122 <para>Continue in the dialplan if the callee hangs up.</para>
125 <para>data-quality (modem) call (minimum delay).</para>
128 <para>Allow <emphasis>callee</emphasis> to hang up by pressing <literal>*</literal>.</para>
131 <para>Allow <emphasis>caller</emphasis> to hang up by pressing <literal>*</literal>.</para>
134 <para>No retries on the timeout; will exit this application and
135 go to the next step.</para>
138 <para>Ignore call forward requests from queue members and do nothing
139 when they are requested.</para>
142 <para>Ring instead of playing MOH. Periodic Announcements are still made, if applicable.</para>
145 <para>Allow the <emphasis>called</emphasis> user to transfer the calling user.</para>
148 <para>Allow the <emphasis>calling</emphasis> user to transfer the call.</para>
151 <para>Allow the <emphasis>called</emphasis> user to write the conversation to
152 disk via Monitor.</para>
155 <para>Allow the <emphasis>calling</emphasis> user to write the conversation to
156 disk via Monitor.</para>
159 <para>Allow the <emphasis>called</emphasis> party to enable parking of the call by sending
160 the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
163 <para>Allow the <emphasis>calling</emphasis> party to enable parking of the call by sending
164 the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
167 <para>Allow the <emphasis>called</emphasis> user to write the conversation
168 to disk via MixMonitor.</para>
171 <para>Allow the <emphasis>calling</emphasis> user to write the conversation to
172 disk via MixMonitor.</para>
176 <parameter name="URL">
177 <para><replaceable>URL</replaceable> will be sent to the called party if the channel supports it.</para>
179 <parameter name="announceoverride" />
180 <parameter name="timeout">
181 <para>Will cause the queue to fail out after a specified number of
182 seconds, checked between each <filename>queues.conf</filename> <replaceable>timeout</replaceable> and
183 <replaceable>retry</replaceable> cycle.</para>
185 <parameter name="AGI">
186 <para>Will setup an AGI script to be executed on the calling party's channel once they are
187 connected to a queue member.</para>
189 <parameter name="macro">
190 <para>Will run a macro on the calling party's channel once they are connected to a queue member.</para>
192 <parameter name="gosub">
193 <para>Will run a gosub on the calling party's channel once they are connected to a queue member.</para>
195 <parameter name="rule">
196 <para>Will cause the queue's defaultrule to be overridden by the rule specified.</para>
200 <para>In addition to transferring the call, a call may be parked and then picked
201 up by another user.</para>
202 <para>This application will return to the dialplan if the queue does not exist, or
203 any of the join options cause the caller to not enter the queue.</para>
204 <para>This application sets the following channel variable upon completion:</para>
206 <variable name="QUEUESTATUS">
207 <para>The status of the call as a text string.</para>
208 <value name="TIMEOUT" />
209 <value name="FULL" />
210 <value name="JOINEMPTY" />
211 <value name="LEAVEEMPTY" />
212 <value name="JOINUNAVAIL" />
213 <value name="LEAVEUNAVAIL" />
214 <value name="CONTINUE" />
219 <ref type="application">AddQueueMember</ref>
220 <ref type="application">RemoveQueueMember</ref>
221 <ref type="application">PauseQueueMember</ref>
222 <ref type="application">UnpauseQueueMember</ref>
223 <ref type="application">AgentLogin</ref>
224 <ref type="function">QUEUE_MEMBER_COUNT</ref>
225 <ref type="function">QUEUE_MEMBER_LIST</ref>
226 <ref type="function">QUEUE_WAITING_COUNT</ref>
229 <application name="AddQueueMember" language="en_US">
231 Dynamically adds queue members.
234 <parameter name="queuename" required="true" />
235 <parameter name="interface" />
236 <parameter name="penalty" />
237 <parameter name="options" />
238 <parameter name="membername" />
239 <parameter name="stateinterface" />
242 <para>Dynamically adds interface to an existing queue. If the interface is
243 already in the queue it will return an error.</para>
244 <para>This application sets the following channel variable upon completion:</para>
246 <variable name="AQMSTATUS">
247 <para>The status of the attempt to add a queue member as a text string.</para>
248 <value name="ADDED" />
249 <value name="MEMBERALREADY" />
250 <value name="NOSUCHQUEUE" />
255 <ref type="application">RemoveQueueMember</ref>
256 <ref type="application">PauseQueueMember</ref>
257 <ref type="application">UnpauseQueueMember</ref>
258 <ref type="application">AgentLogin</ref>
261 <application name="RemoveQueueMember" language="en_US">
263 Dynamically removes queue members.
266 <parameter name="queuename" required="true" />
267 <parameter name="interface" />
268 <parameter name="options" />
271 <para>If the interface is <emphasis>NOT</emphasis> in the queue it will return an error.</para>
272 <para>This application sets the following channel variable upon completion:</para>
274 <variable name="RQMSTATUS">
275 <value name="REMOVED" />
276 <value name="NOTINQUEUE" />
277 <value name="NOSUCHQUEUE" />
280 <para>Example: RemoveQueueMember(techsupport,SIP/3000)</para>
283 <ref type="application">Queue</ref>
284 <ref type="application">AddQueueMember</ref>
285 <ref type="application">PauseQueueMember</ref>
286 <ref type="application">UnpauseQueueMember</ref>
289 <application name="PauseQueueMember" language="en_US">
291 Pauses a queue member.
294 <parameter name="queuename" />
295 <parameter name="interface" required="true" />
296 <parameter name="options" />
297 <parameter name="reason">
298 <para>Is used to add extra information to the appropriate queue_log entries and manager events.</para>
302 <para>Pauses (blocks calls for) a queue member. The given interface will be paused in the given queue.
303 This prevents any calls from being sent from the queue to the interface until it is
304 unpaused with UnpauseQueueMember or the manager interface. If no queuename is given,
305 the interface is paused in every queue it is a member of. The application will fail if the
306 interface is not found.</para>
307 <para>This application sets the following channel variable upon completion:</para>
309 <variable name="PQMSTATUS">
310 <para>The status of the attempt to pause a queue member as a text string.</para>
311 <value name="PAUSED" />
312 <value name="NOTFOUND" />
315 <para>Example: PauseQueueMember(,SIP/3000)</para>
318 <ref type="application">UnpauseQueueMember</ref>
321 <application name="UnpauseQueueMember" language="en_US">
323 Unpauses a queue member.
326 <parameter name="queuename" />
327 <parameter name="interface" required="true" />
328 <parameter name="options" />
329 <parameter name="reason">
330 <para>Is used to add extra information to the appropriate queue_log entries and manager events.</para>
334 <para>Unpauses (resumes calls to) a queue member. This is the counterpart to <literal>PauseQueueMember()</literal>
335 and operates exactly the same way, except it unpauses instead of pausing the given interface.</para>
336 <para>This application sets the following channel variable upon completion:</para>
338 <variable name="UPQMSTATUS">
339 <para>The status of the attempt to unpause a queue member as a text string.</para>
340 <value name="UNPAUSED" />
341 <value name="NOTFOUND" />
344 <para>Example: UnpauseQueueMember(,SIP/3000)</para>
347 <ref type="application">PauseQueueMember</ref>
350 <application name="QueueLog" language="en_US">
352 Writes to the queue_log file.
355 <parameter name="queuename" required="true" />
356 <parameter name="uniqueid" required="true" />
357 <parameter name="agent" required="true" />
358 <parameter name="event" required="true" />
359 <parameter name="additionalinfo" />
362 <para>Allows you to write your own events into the queue log.</para>
363 <para>Example: QueueLog(101,${UNIQUEID},${AGENT},WENTONBREAK,600)</para>
366 <ref type="application">Queue</ref>
369 <function name="QUEUE_VARIABLES" language="en_US">
371 Return Queue information in variables.
374 <parameter name="queuename" required="true">
376 <enum name="QUEUEMAX">
377 <para>Maxmimum number of calls allowed.</para>
379 <enum name="QUEUESTRATEGY">
380 <para>The strategy of the queue.</para>
382 <enum name="QUEUECALLS">
383 <para>Number of calls currently in the queue.</para>
385 <enum name="QUEUEHOLDTIME">
386 <para>Current average hold time.</para>
388 <enum name="QUEUECOMPLETED">
389 <para>Number of completed calls for the queue.</para>
391 <enum name="QUEUEABANDONED">
392 <para>Number of abandoned calls.</para>
394 <enum name="QUEUESRVLEVEL">
395 <para>Queue service level.</para>
397 <enum name="QUEUESRVLEVELPERF">
398 <para>Current service level performance.</para>
404 <para>Makes the following queue variables available.</para>
405 <para>Returns <literal>0</literal> if queue is found and setqueuevar is defined, <literal>-1</literal> otherwise.</para>
408 <function name="QUEUE_MEMBER" language="en_US">
410 Count number of members answering a queue.
413 <parameter name="queuename" required="true" />
414 <parameter name="option" required="true">
417 <para>Returns the number of logged-in members for the specified queue.</para>
420 <para>Returns the number of logged-in members for the specified queue available to take a call.</para>
423 <para>Returns the total number of members for the specified queue.</para>
429 <para>Returns the number of members currently associated with the specified <replaceable>queuename</replaceable>.</para>
432 <function name="QUEUE_MEMBER_COUNT" language="en_US">
434 Count number of members answering a queue.
437 <parameter name="queuename" required="true" />
440 <para>Returns the number of members currently associated with the specified <replaceable>queuename</replaceable>.</para>
441 <warning><para>This function has been deprecated in favor of the <literal>QUEUE_MEMBER()</literal> function</para></warning>
444 <ref type="function">QUEUE_MEMBER_LIST</ref>
447 <function name="QUEUE_WAITING_COUNT" language="en_US">
449 Count number of calls currently waiting in a queue.
452 <parameter name="queuename" />
455 <para>Returns the number of callers currently waiting in the specified <replaceable>queuename</replaceable>.</para>
458 <function name="QUEUE_MEMBER_LIST" language="en_US">
460 Returns a list of interfaces on a queue.
463 <parameter name="queuename" required="true" />
466 <para>Returns a comma-separated list of members associated with the specified <replaceable>queuename</replaceable>.</para>
469 <ref type="function">QUEUE_MEMBER_COUNT</ref>
472 <function name="QUEUE_MEMBER_PENALTY" language="en_US">
474 Gets or sets queue members penalty.
477 <parameter name="queuename" required="true" />
478 <parameter name="interface" required="true" />
481 <para>Gets or sets queue members penalty.</para>
488 QUEUE_STRATEGY_RINGALL = 0,
489 QUEUE_STRATEGY_LEASTRECENT,
490 QUEUE_STRATEGY_FEWESTCALLS,
491 QUEUE_STRATEGY_RANDOM,
492 QUEUE_STRATEGY_RRMEMORY,
493 QUEUE_STRATEGY_LINEAR,
494 QUEUE_STRATEGY_WRANDOM
497 static const struct strategy {
501 { QUEUE_STRATEGY_RINGALL, "ringall" },
502 { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
503 { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
504 { QUEUE_STRATEGY_RANDOM, "random" },
505 { QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
506 { QUEUE_STRATEGY_RRMEMORY, "roundrobin" },
507 { QUEUE_STRATEGY_LINEAR, "linear" },
508 { QUEUE_STRATEGY_WRANDOM, "wrandom"},
511 static struct ast_taskprocessor *devicestate_tps;
513 #define DEFAULT_RETRY 5
514 #define DEFAULT_TIMEOUT 15
515 #define RECHECK 1 /*!< Recheck every second to see we we're at the top yet */
516 #define MAX_PERIODIC_ANNOUNCEMENTS 10 /*!< The maximum periodic announcements we can have */
517 #define DEFAULT_MIN_ANNOUNCE_FREQUENCY 15 /*!< The minimum number of seconds between position announcements \
518 The default value of 15 provides backwards compatibility */
519 #define MAX_QUEUE_BUCKETS 53
521 #define RES_OKAY 0 /*!< Action completed */
522 #define RES_EXISTS (-1) /*!< Entry already exists */
523 #define RES_OUTOFMEMORY (-2) /*!< Out of memory */
524 #define RES_NOSUCHQUEUE (-3) /*!< No such queue */
525 #define RES_NOT_DYNAMIC (-4) /*!< Member is not dynamic */
527 static char *app = "Queue";
529 static char *app_aqm = "AddQueueMember" ;
531 static char *app_rqm = "RemoveQueueMember" ;
533 static char *app_pqm = "PauseQueueMember" ;
535 static char *app_upqm = "UnpauseQueueMember" ;
537 static char *app_ql = "QueueLog" ;
539 /*! \brief Persistent Members astdb family */
540 static const char *pm_family = "Queue/PersistentMembers";
541 /* The maximum length of each persistent member queue database entry */
542 #define PM_MAX_LEN 8192
544 /*! \brief queues.conf [general] option */
545 static int queue_keep_stats = 0;
547 /*! \brief queues.conf [general] option */
548 static int queue_persistent_members = 0;
550 /*! \brief queues.conf per-queue weight option */
551 static int use_weight = 0;
553 /*! \brief queues.conf [general] option */
554 static int autofill_default = 0;
556 /*! \brief queues.conf [general] option */
557 static int montype_default = 0;
559 /*! \brief queues.conf [general] option */
560 static int shared_lastcall = 0;
562 /*! \brief Subscription to device state change events */
563 static struct ast_event_sub *device_state_sub;
565 /*! \brief queues.conf [general] option */
566 static int update_cdr = 0;
572 QUEUE_LEAVEEMPTY = 3,
573 QUEUE_JOINUNAVAIL = 4,
574 QUEUE_LEAVEUNAVAIL = 5,
580 enum queue_result id;
582 } queue_results[] = {
583 { QUEUE_UNKNOWN, "UNKNOWN" },
584 { QUEUE_TIMEOUT, "TIMEOUT" },
585 { QUEUE_JOINEMPTY,"JOINEMPTY" },
586 { QUEUE_LEAVEEMPTY, "LEAVEEMPTY" },
587 { QUEUE_JOINUNAVAIL, "JOINUNAVAIL" },
588 { QUEUE_LEAVEUNAVAIL, "LEAVEUNAVAIL" },
589 { QUEUE_FULL, "FULL" },
590 { QUEUE_CONTINUE, "CONTINUE" },
593 enum queue_timeout_priority {
594 TIMEOUT_PRIORITY_APP,
595 TIMEOUT_PRIORITY_CONF,
598 /*! \brief We define a custom "local user" structure because we
599 * use it not only for keeping track of what is in use but
600 * also for keeping track of who we're dialing.
602 * There are two "links" defined in this structure, q_next and call_next.
603 * q_next links ALL defined callattempt structures into a linked list. call_next is
604 * a link which allows for a subset of the callattempts to be traversed. This subset
605 * is used in wait_for_answer so that irrelevant callattempts are not traversed. This
606 * also is helpful so that queue logs are always accurate in the case where a call to
607 * a member times out, especially if using the ringall strategy.
611 struct callattempt *q_next;
612 struct callattempt *call_next;
613 struct ast_channel *chan;
619 struct call_queue *lastqueue;
620 struct member *member;
625 struct call_queue *parent; /*!< What queue is our parent */
626 char moh[80]; /*!< Name of musiconhold to be used */
627 char announce[80]; /*!< Announcement to play for member when call is answered */
628 char context[AST_MAX_CONTEXT]; /*!< Context when user exits queue */
629 char digits[AST_MAX_EXTENSION]; /*!< Digits entered while in queue */
630 int valid_digits; /*!< Digits entered correspond to valid extension. Exited */
631 int pos; /*!< Where we are in the queue */
632 int prio; /*!< Our priority */
633 int last_pos_said; /*!< Last position we told the user */
634 time_t last_periodic_announce_time; /*!< The last time we played a periodic announcement */
635 int last_periodic_announce_sound; /*!< The last periodic announcement we made */
636 time_t last_pos; /*!< Last time we told the user their position */
637 int opos; /*!< Where we started in the queue */
638 int handled; /*!< Whether our call was handled */
639 int pending; /*!< Non-zero if we are attempting to call a member */
640 int max_penalty; /*!< Limit the members that can take this call to this penalty or lower */
641 int min_penalty; /*!< Limit the members that can take this call to this penalty or higher */
642 int linpos; /*!< If using linear strategy, what position are we at? */
643 int linwrapped; /*!< Is the linpos wrapped? */
644 time_t start; /*!< When we started holding */
645 time_t expire; /*!< When this entry should expire (time out of queue) */
646 struct ast_channel *chan; /*!< Our channel */
647 AST_LIST_HEAD_NOLOCK(,penalty_rule) qe_rules; /*!< Local copy of the queue's penalty rules */
648 struct penalty_rule *pr; /*!< Pointer to the next penalty rule to implement */
649 struct queue_ent *next; /*!< The next queue entry */
653 char interface[80]; /*!< Technology/Location to dial to reach this member*/
654 char state_interface[80]; /*!< Technology/Location from which to read devicestate changes */
655 char membername[80]; /*!< Member name to use in queue logs */
656 int penalty; /*!< Are we a last resort? */
657 int calls; /*!< Number of calls serviced by this member */
658 int dynamic; /*!< Are we dynamically added? */
659 int realtime; /*!< Is this member realtime? */
660 int status; /*!< Status of queue member */
661 int paused; /*!< Are we paused (not accepting calls)? */
662 time_t lastcall; /*!< When last successful call was hungup */
663 struct call_queue *lastqueue; /*!< Last queue we received a call */
664 unsigned int dead:1; /*!< Used to detect members deleted in realtime */
665 unsigned int delme:1; /*!< Flag to delete entry on reload */
666 char rt_uniqueid[80]; /*!< Unique id of realtime member entry */
669 enum empty_conditions {
670 QUEUE_EMPTY_PENALTY = (1 << 0),
671 QUEUE_EMPTY_PAUSED = (1 << 1),
672 QUEUE_EMPTY_INUSE = (1 << 2),
673 QUEUE_EMPTY_RINGING = (1 << 3),
674 QUEUE_EMPTY_UNAVAILABLE = (1 << 4),
675 QUEUE_EMPTY_INVALID = (1 << 5),
676 QUEUE_EMPTY_UNKNOWN = (1 << 6),
677 QUEUE_EMPTY_WRAPUP = (1 << 7),
680 /* values used in multi-bit flags in call_queue */
681 #define ANNOUNCEHOLDTIME_ALWAYS 1
682 #define ANNOUNCEHOLDTIME_ONCE 2
683 #define QUEUE_EVENT_VARIABLES 3
685 struct penalty_rule {
686 int time; /*!< Number of seconds that need to pass before applying this rule */
687 int max_value; /*!< The amount specified in the penalty rule for max penalty */
688 int min_value; /*!< The amount specified in the penalty rule for min penalty */
689 int max_relative; /*!< Is the max adjustment relative? 1 for relative, 0 for absolute */
690 int min_relative; /*!< Is the min adjustment relative? 1 for relative, 0 for absolute */
691 AST_LIST_ENTRY(penalty_rule) list; /*!< Next penalty_rule */
694 #define ANNOUNCEPOSITION_YES 1 /*!< We announce position */
695 #define ANNOUNCEPOSITION_NO 2 /*!< We don't announce position */
696 #define ANNOUNCEPOSITION_MORE_THAN 3 /*!< We say "Currently there are more than <limit>" */
697 #define ANNOUNCEPOSITION_LIMIT 4 /*!< We not announce position more than <limit> */
700 AST_DECLARE_STRING_FIELDS(
702 AST_STRING_FIELD(name);
703 /*! Music on Hold class */
704 AST_STRING_FIELD(moh);
705 /*! Announcement to play when call is answered */
706 AST_STRING_FIELD(announce);
708 AST_STRING_FIELD(context);
709 /*! Macro to run upon member connection */
710 AST_STRING_FIELD(membermacro);
711 /*! Gosub to run upon member connection */
712 AST_STRING_FIELD(membergosub);
713 /*! Default rule to use if none specified in call to Queue() */
714 AST_STRING_FIELD(defaultrule);
715 /*! Sound file: "Your call is now first in line" (def. queue-youarenext) */
716 AST_STRING_FIELD(sound_next);
717 /*! Sound file: "There are currently" (def. queue-thereare) */
718 AST_STRING_FIELD(sound_thereare);
719 /*! Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting) */
720 AST_STRING_FIELD(sound_calls);
721 /*! Sound file: "Currently there are more than" (def. queue-quantity1) */
722 AST_STRING_FIELD(queue_quantity1);
723 /*! Sound file: "callers waiting to speak with a representative" (def. queue-quantity2) */
724 AST_STRING_FIELD(queue_quantity2);
725 /*! Sound file: "The current estimated total holdtime is" (def. queue-holdtime) */
726 AST_STRING_FIELD(sound_holdtime);
727 /*! Sound file: "minutes." (def. queue-minutes) */
728 AST_STRING_FIELD(sound_minutes);
729 /*! Sound file: "minute." (def. queue-minute) */
730 AST_STRING_FIELD(sound_minute);
731 /*! Sound file: "seconds." (def. queue-seconds) */
732 AST_STRING_FIELD(sound_seconds);
733 /*! Sound file: "Thank you for your patience." (def. queue-thankyou) */
734 AST_STRING_FIELD(sound_thanks);
735 /*! Sound file: Custom announce for caller, no default */
736 AST_STRING_FIELD(sound_callerannounce);
737 /*! Sound file: "Hold time" (def. queue-reporthold) */
738 AST_STRING_FIELD(sound_reporthold);
740 /*! Sound files: Custom announce, no default */
741 struct ast_str *sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS];
743 unsigned int eventwhencalled:2;
744 unsigned int ringinuse:1;
745 unsigned int setinterfacevar:1;
746 unsigned int setqueuevar:1;
747 unsigned int setqueueentryvar:1;
748 unsigned int reportholdtime:1;
749 unsigned int wrapped:1;
750 unsigned int timeoutrestart:1;
751 unsigned int announceholdtime:2;
752 unsigned int announceposition:3;
754 unsigned int maskmemberstatus:1;
755 unsigned int realtime:1;
756 unsigned int found:1;
757 enum empty_conditions joinempty;
758 enum empty_conditions leavewhenempty;
759 int announcepositionlimit; /*!< How many positions we announce? */
760 int announcefrequency; /*!< How often to announce their position */
761 int minannouncefrequency; /*!< The minimum number of seconds between position announcements (def. 15) */
762 int periodicannouncefrequency; /*!< How often to play periodic announcement */
763 int numperiodicannounce; /*!< The number of periodic announcements configured */
764 int randomperiodicannounce; /*!< Are periodic announcments randomly chosen */
765 int roundingseconds; /*!< How many seconds do we round to? */
766 int holdtime; /*!< Current avg holdtime, based on an exponential average */
767 int talktime; /*!< Current avg talktime, based on the same exponential average */
768 int callscompleted; /*!< Number of queue calls completed */
769 int callsabandoned; /*!< Number of queue calls abandoned */
770 int servicelevel; /*!< seconds setting for servicelevel*/
771 int callscompletedinsl; /*!< Number of calls answered with servicelevel*/
772 char monfmt[8]; /*!< Format to use when recording calls */
773 int montype; /*!< Monitor type Monitor vs. MixMonitor */
774 int count; /*!< How many entries */
775 int maxlen; /*!< Max number of entries */
776 int wrapuptime; /*!< Wrapup Time */
778 int retry; /*!< Retry calling everyone after this amount of time */
779 int timeout; /*!< How long to wait for an answer */
780 int weight; /*!< Respective weight */
781 int autopause; /*!< Auto pause queue members if they fail to answer */
782 int timeoutpriority; /*!< Do we allow a fraction of the timeout to occur for a ring? */
784 /* Queue strategy things */
785 int rrpos; /*!< Round Robin - position */
786 int memberdelay; /*!< Seconds to delay connecting member to caller */
787 int autofill; /*!< Ignore the head call status and ring an available agent */
789 struct ao2_container *members; /*!< Head of the list of members */
791 * \brief Number of members _logged in_
792 * \note There will be members in the members container that are not logged
793 * in, so this can not simply be replaced with ao2_container_count().
796 struct queue_ent *head; /*!< Head of the list of callers */
797 AST_LIST_ENTRY(call_queue) list; /*!< Next call queue */
798 AST_LIST_HEAD_NOLOCK(, penalty_rule) rules; /*!< The list of penalty rules to invoke */
803 AST_LIST_HEAD_NOLOCK(,penalty_rule) rules;
804 AST_LIST_ENTRY(rule_list) list;
807 AST_LIST_HEAD_STATIC(rule_lists, rule_list);
809 static struct ao2_container *queues;
811 static void update_realtime_members(struct call_queue *q);
812 static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
814 static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
815 /*! \brief sets the QUEUESTATUS channel variable */
816 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
820 for (i = 0; i < ARRAY_LEN(queue_results); i++) {
821 if (queue_results[i].id == res) {
822 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
828 static const char *int2strat(int strategy)
832 for (x = 0; x < ARRAY_LEN(strategies); x++) {
833 if (strategy == strategies[x].strategy)
834 return strategies[x].name;
840 static int strat2int(const char *strategy)
844 for (x = 0; x < ARRAY_LEN(strategies); x++) {
845 if (!strcasecmp(strategy, strategies[x].name))
846 return strategies[x].strategy;
852 static int queue_hash_cb(const void *obj, const int flags)
854 const struct call_queue *q = obj;
856 return ast_str_case_hash(q->name);
859 static int queue_cmp_cb(void *obj, void *arg, int flags)
861 struct call_queue *q = obj, *q2 = arg;
862 return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0;
865 static inline struct call_queue *queue_ref(struct call_queue *q)
871 static inline struct call_queue *queue_unref(struct call_queue *q)
877 /*! \brief Set variables of queue */
878 static void set_queue_variables(struct queue_ent *qe)
880 char interfacevar[256]="";
883 if (qe->parent->setqueuevar) {
885 if (qe->parent->callscompleted > 0)
886 sl = 100 * ((float) qe->parent->callscompletedinsl / (float) qe->parent->callscompleted);
888 snprintf(interfacevar, sizeof(interfacevar),
889 "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
890 qe->parent->name, qe->parent->maxlen, int2strat(qe->parent->strategy), qe->parent->count, qe->parent->holdtime, qe->parent->talktime, qe->parent->callscompleted,
891 qe->parent->callsabandoned, qe->parent->servicelevel, sl);
893 pbx_builtin_setvar_multiple(qe->chan, interfacevar);
897 /*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
898 static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
900 struct queue_ent *cur;
917 /*! \brief Check if members are available
919 * This function checks to see if members are available to be called. If any member
920 * is available, the function immediately returns 0. If no members are available,
921 * then -1 is returned.
923 static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, enum empty_conditions conditions)
925 struct member *member;
926 struct ao2_iterator mem_iter;
929 mem_iter = ao2_iterator_init(q->members, 0);
930 for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
931 if ((max_penalty && (member->penalty > max_penalty)) || (min_penalty && (member->penalty < min_penalty))) {
932 if (conditions & QUEUE_EMPTY_PENALTY) {
933 ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
938 switch (member->status) {
939 case AST_DEVICE_INVALID:
940 if (conditions & QUEUE_EMPTY_INVALID) {
941 ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername);
944 case AST_DEVICE_UNAVAILABLE:
945 if (conditions & QUEUE_EMPTY_UNAVAILABLE) {
946 ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername);
949 case AST_DEVICE_INUSE:
950 if (conditions & QUEUE_EMPTY_INUSE) {
951 ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername);
954 case AST_DEVICE_UNKNOWN:
955 if (conditions & QUEUE_EMPTY_UNKNOWN) {
956 ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername);
960 if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) {
961 ast_debug(4, "%s is unavailable because he is paused'\n", member->membername);
963 } else if ((conditions & QUEUE_EMPTY_WRAPUP) && member->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < member->lastcall)) {
964 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);
969 ast_debug(4, "%s is available.\n", member->membername);
981 AST_LIST_ENTRY(statechange) entry;
986 /*! \brief set a member's status based on device state of that member's state_interface.
988 * Lock interface list find sc, iterate through each queues queue_member list for member to
989 * update state inside queues
991 static int update_status(struct call_queue *q, struct member *m, const int status)
995 if (q->maskmemberstatus)
998 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
1001 "MemberName: %s\r\n"
1002 "Membership: %s\r\n"
1004 "CallsTaken: %d\r\n"
1008 q->name, m->interface, m->membername, m->dynamic ? "dynamic" : m->realtime ? "realtime" : "static",
1009 m->penalty, m->calls, (int)m->lastcall, m->status, m->paused
1015 /*! \brief set a member's status based on device state of that member's interface*/
1016 static int handle_statechange(void *datap)
1018 struct statechange *sc = datap;
1019 struct ao2_iterator miter, qiter;
1021 struct call_queue *q;
1022 char interface[80], *slash_pos;
1025 qiter = ao2_iterator_init(queues, 0);
1027 while ((q = ao2_iterator_next(&qiter))) {
1030 miter = ao2_iterator_init(q->members, 0);
1031 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
1032 ast_copy_string(interface, m->state_interface, sizeof(interface));
1034 if ((slash_pos = strchr(interface, '/')))
1035 if ((slash_pos = strchr(slash_pos + 1, '/')))
1038 if (!strcasecmp(interface, sc->dev)) {
1040 update_status(q, m, sc->state);
1050 ast_debug(1, "Device '%s' changed to state '%d' (%s)\n", sc->dev, sc->state, ast_devstate2str(sc->state));
1052 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));
1058 static void device_state_cb(const struct ast_event *event, void *unused)
1060 enum ast_device_state state;
1062 struct statechange *sc;
1065 state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
1066 device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
1068 if (ast_strlen_zero(device)) {
1069 ast_log(LOG_ERROR, "Received invalid event that had no device IE\n");
1072 datapsize = sizeof(*sc) + strlen(device) + 1;
1073 if (!(sc = ast_calloc(1, datapsize))) {
1074 ast_log(LOG_ERROR, "failed to calloc a state change struct\n");
1078 strcpy(sc->dev, device);
1079 if (ast_taskprocessor_push(devicestate_tps, handle_statechange, sc) < 0) {
1084 /*! \brief allocate space for new queue member and set fields based on parameters passed */
1085 static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface)
1089 if ((cur = ao2_alloc(sizeof(*cur), NULL))) {
1090 cur->penalty = penalty;
1091 cur->paused = paused;
1092 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
1093 if (!ast_strlen_zero(state_interface))
1094 ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface));
1096 ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface));
1097 if (!ast_strlen_zero(membername))
1098 ast_copy_string(cur->membername, membername, sizeof(cur->membername));
1100 ast_copy_string(cur->membername, interface, sizeof(cur->membername));
1101 if (!strchr(cur->interface, '/'))
1102 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
1103 cur->status = ast_device_state(cur->state_interface);
1110 static int compress_char(const char c)
1120 static int member_hash_fn(const void *obj, const int flags)
1122 const struct member *mem = obj;
1123 const char *chname = strchr(mem->interface, '/');
1126 chname = mem->interface;
1127 for (i = 0; i < 5 && chname[i]; i++)
1128 ret += compress_char(chname[i]) << (i * 6);
1132 static int member_cmp_fn(void *obj1, void *obj2, int flags)
1134 struct member *mem1 = obj1, *mem2 = obj2;
1135 return strcasecmp(mem1->interface, mem2->interface) ? 0 : CMP_MATCH | CMP_STOP;
1139 * \brief Initialize Queue default values.
1140 * \note the queue's lock must be held before executing this function
1142 static void init_queue(struct call_queue *q)
1145 struct penalty_rule *pr_iter;
1148 q->retry = DEFAULT_RETRY;
1149 q->timeout = DEFAULT_TIMEOUT;
1151 q->announcefrequency = 0;
1152 q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY;
1153 q->announceholdtime = 1;
1154 q->announcepositionlimit = 10; /* Default 10 positions */
1155 q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */
1156 q->roundingseconds = 0; /* Default - don't announce seconds */
1157 q->servicelevel = 0;
1159 q->setinterfacevar = 0;
1161 q->setqueueentryvar = 0;
1162 q->autofill = autofill_default;
1163 q->montype = montype_default;
1164 q->monfmt[0] = '\0';
1165 q->reportholdtime = 0;
1168 q->leavewhenempty = 0;
1170 q->maskmemberstatus = 0;
1171 q->eventwhencalled = 0;
1173 q->timeoutrestart = 0;
1174 q->periodicannouncefrequency = 0;
1175 q->randomperiodicannounce = 0;
1176 q->numperiodicannounce = 0;
1177 q->timeoutpriority = TIMEOUT_PRIORITY_APP;
1179 if (q->strategy == QUEUE_STRATEGY_LINEAR)
1180 /* linear strategy depends on order, so we have to place all members in a single bucket */
1181 q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn);
1183 q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
1188 ast_string_field_set(q, sound_next, "queue-youarenext");
1189 ast_string_field_set(q, sound_thereare, "queue-thereare");
1190 ast_string_field_set(q, sound_calls, "queue-callswaiting");
1191 ast_string_field_set(q, queue_quantity1, "queue-quantity1");
1192 ast_string_field_set(q, queue_quantity2, "queue-quantity2");
1193 ast_string_field_set(q, sound_holdtime, "queue-holdtime");
1194 ast_string_field_set(q, sound_minutes, "queue-minutes");
1195 ast_string_field_set(q, sound_minute, "queue-minute");
1196 ast_string_field_set(q, sound_seconds, "queue-seconds");
1197 ast_string_field_set(q, sound_thanks, "queue-thankyou");
1198 ast_string_field_set(q, sound_reporthold, "queue-reporthold");
1200 if ((q->sound_periodicannounce[0] = ast_str_create(32)))
1201 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
1203 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
1204 if (q->sound_periodicannounce[i])
1205 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
1208 while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list)))
1212 static void clear_queue(struct call_queue *q)
1215 q->callscompleted = 0;
1216 q->callsabandoned = 0;
1217 q->callscompletedinsl = 0;
1222 * \brief Change queue penalty by adding rule.
1224 * Check rule for errors with time or fomatting, see if rule is relative to rest
1225 * of queue, iterate list of rules to find correct insertion point, insert and return.
1226 * \retval -1 on failure
1227 * \retval 0 on success
1228 * \note Call this with the rule_lists locked
1230 static int insert_penaltychange (const char *list_name, const char *content, const int linenum)
1232 char *timestr, *maxstr, *minstr, *contentdup;
1233 struct penalty_rule *rule = NULL, *rule_iter;
1234 struct rule_list *rl_iter;
1235 int penaltychangetime, inserted = 0;
1237 if (!(rule = ast_calloc(1, sizeof(*rule)))) {
1238 ast_log(LOG_ERROR, "Cannot allocate memory for penaltychange rule at line %d!\n", linenum);
1242 contentdup = ast_strdupa(content);
1244 if (!(maxstr = strchr(contentdup, ','))) {
1245 ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum);
1251 timestr = contentdup;
1253 if ((penaltychangetime = atoi(timestr)) < 0) {
1254 ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum);
1259 rule->time = penaltychangetime;
1261 if ((minstr = strchr(maxstr,',')))
1264 /* The last check will evaluate true if either no penalty change is indicated for a given rule
1265 * OR if a min penalty change is indicated but no max penalty change is */
1266 if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') {
1267 rule->max_relative = 1;
1270 rule->max_value = atoi(maxstr);
1272 if (!ast_strlen_zero(minstr)) {
1273 if (*minstr == '+' || *minstr == '-')
1274 rule->min_relative = 1;
1275 rule->min_value = atoi(minstr);
1276 } else /*there was no minimum specified, so assume this means no change*/
1277 rule->min_relative = 1;
1279 /*We have the rule made, now we need to insert it where it belongs*/
1280 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){
1281 if (strcasecmp(rl_iter->name, list_name))
1284 AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) {
1285 if (rule->time < rule_iter->time) {
1286 AST_LIST_INSERT_BEFORE_CURRENT(rule, list);
1291 AST_LIST_TRAVERSE_SAFE_END;
1294 AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list);
1301 static void parse_empty_options(const char *value, enum empty_conditions *empty)
1303 char *value_copy = ast_strdupa(value);
1304 char *option = NULL;
1305 while ((option = strsep(&value_copy, ","))) {
1306 if (!strcasecmp(option, "paused")) {
1307 *empty |= QUEUE_EMPTY_PAUSED;
1308 } else if (!strcasecmp(option, "penalty")) {
1309 *empty |= QUEUE_EMPTY_PENALTY;
1310 } else if (!strcasecmp(option, "inuse")) {
1311 *empty |= QUEUE_EMPTY_INUSE;
1312 } else if (!strcasecmp(option, "ringing")) {
1313 *empty |= QUEUE_EMPTY_RINGING;
1314 } else if (!strcasecmp(option, "invalid")) {
1315 *empty |= QUEUE_EMPTY_INVALID;
1316 } else if (!strcasecmp(option, "wrapup")) {
1317 *empty |= QUEUE_EMPTY_WRAPUP;
1318 } else if (!strcasecmp(option, "unavailable")) {
1319 *empty |= QUEUE_EMPTY_UNAVAILABLE;
1320 } else if (!strcasecmp(option, "unknown")) {
1321 *empty |= QUEUE_EMPTY_UNKNOWN;
1322 } else if (!strcasecmp(option, "loose")) {
1323 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID);
1324 } else if (!strcasecmp(option, "strict")) {
1325 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED | QUEUE_EMPTY_UNAVAILABLE);
1326 } else if (ast_false(option)) {
1327 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED);
1328 } else if (ast_true(option)) {
1334 /*! \brief Configure a queue parameter.
1336 * The failunknown flag is set for config files (and static realtime) to show
1337 * errors for unknown parameters. It is cleared for dynamic realtime to allow
1338 * extra fields in the tables.
1339 * \note For error reporting, line number is passed for .conf static configuration,
1340 * for Realtime queues, linenum is -1.
1342 static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
1344 if (!strcasecmp(param, "musicclass") ||
1345 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
1346 ast_string_field_set(q, moh, val);
1347 } else if (!strcasecmp(param, "announce")) {
1348 ast_string_field_set(q, announce, val);
1349 } else if (!strcasecmp(param, "context")) {
1350 ast_string_field_set(q, context, val);
1351 } else if (!strcasecmp(param, "timeout")) {
1352 q->timeout = atoi(val);
1354 q->timeout = DEFAULT_TIMEOUT;
1355 } else if (!strcasecmp(param, "ringinuse")) {
1356 q->ringinuse = ast_true(val);
1357 } else if (!strcasecmp(param, "setinterfacevar")) {
1358 q->setinterfacevar = ast_true(val);
1359 } else if (!strcasecmp(param, "setqueuevar")) {
1360 q->setqueuevar = ast_true(val);
1361 } else if (!strcasecmp(param, "setqueueentryvar")) {
1362 q->setqueueentryvar = ast_true(val);
1363 } else if (!strcasecmp(param, "monitor-format")) {
1364 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
1365 } else if (!strcasecmp(param, "membermacro")) {
1366 ast_string_field_set(q, membermacro, val);
1367 } else if (!strcasecmp(param, "membergosub")) {
1368 ast_string_field_set(q, membergosub, val);
1369 } else if (!strcasecmp(param, "queue-youarenext")) {
1370 ast_string_field_set(q, sound_next, val);
1371 } else if (!strcasecmp(param, "queue-thereare")) {
1372 ast_string_field_set(q, sound_thereare, val);
1373 } else if (!strcasecmp(param, "queue-callswaiting")) {
1374 ast_string_field_set(q, sound_calls, val);
1375 } else if (!strcasecmp(param, "queue-quantity1")) {
1376 ast_string_field_set(q, queue_quantity1, val);
1377 } else if (!strcasecmp(param, "queue-quantity2")) {
1378 ast_string_field_set(q, queue_quantity2, val);
1379 } else if (!strcasecmp(param, "queue-holdtime")) {
1380 ast_string_field_set(q, sound_holdtime, val);
1381 } else if (!strcasecmp(param, "queue-minutes")) {
1382 ast_string_field_set(q, sound_minutes, val);
1383 } else if (!strcasecmp(param, "queue-minute")) {
1384 ast_string_field_set(q, sound_minute, val);
1385 } else if (!strcasecmp(param, "queue-seconds")) {
1386 ast_string_field_set(q, sound_seconds, val);
1387 } else if (!strcasecmp(param, "queue-thankyou")) {
1388 ast_string_field_set(q, sound_thanks, val);
1389 } else if (!strcasecmp(param, "queue-callerannounce")) {
1390 ast_string_field_set(q, sound_callerannounce, val);
1391 } else if (!strcasecmp(param, "queue-reporthold")) {
1392 ast_string_field_set(q, sound_reporthold, val);
1393 } else if (!strcasecmp(param, "announce-frequency")) {
1394 q->announcefrequency = atoi(val);
1395 } else if (!strcasecmp(param, "min-announce-frequency")) {
1396 q->minannouncefrequency = atoi(val);
1397 ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name);
1398 } else if (!strcasecmp(param, "announce-round-seconds")) {
1399 q->roundingseconds = atoi(val);
1400 /* Rounding to any other values just doesn't make sense... */
1401 if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10
1402 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) {
1404 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
1405 "using 0 instead for queue '%s' at line %d of queues.conf\n",
1406 val, param, q->name, linenum);
1408 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
1409 "using 0 instead for queue '%s'\n", val, param, q->name);
1411 q->roundingseconds=0;
1413 } else if (!strcasecmp(param, "announce-holdtime")) {
1414 if (!strcasecmp(val, "once"))
1415 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
1416 else if (ast_true(val))
1417 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
1419 q->announceholdtime = 0;
1420 } else if (!strcasecmp(param, "announce-position")) {
1421 if (!strcasecmp(val, "limit"))
1422 q->announceposition = ANNOUNCEPOSITION_LIMIT;
1423 else if (!strcasecmp(val, "more"))
1424 q->announceposition = ANNOUNCEPOSITION_MORE_THAN;
1425 else if (ast_true(val))
1426 q->announceposition = ANNOUNCEPOSITION_YES;
1428 q->announceposition = ANNOUNCEPOSITION_NO;
1429 } else if (!strcasecmp(param, "announce-position-limit")) {
1430 q->announcepositionlimit = atoi(val);
1431 } else if (!strcasecmp(param, "periodic-announce")) {
1432 if (strchr(val, ',')) {
1433 char *s, *buf = ast_strdupa(val);
1436 while ((s = strsep(&buf, ",|"))) {
1437 if (!q->sound_periodicannounce[i])
1438 q->sound_periodicannounce[i] = ast_str_create(16);
1439 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s);
1441 if (i == MAX_PERIODIC_ANNOUNCEMENTS)
1444 q->numperiodicannounce = i;
1446 ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val);
1447 q->numperiodicannounce = 1;
1449 } else if (!strcasecmp(param, "periodic-announce-frequency")) {
1450 q->periodicannouncefrequency = atoi(val);
1451 } else if (!strcasecmp(param, "random-periodic-announce")) {
1452 q->randomperiodicannounce = ast_true(val);
1453 } else if (!strcasecmp(param, "retry")) {
1454 q->retry = atoi(val);
1456 q->retry = DEFAULT_RETRY;
1457 } else if (!strcasecmp(param, "wrapuptime")) {
1458 q->wrapuptime = atoi(val);
1459 } else if (!strcasecmp(param, "autofill")) {
1460 q->autofill = ast_true(val);
1461 } else if (!strcasecmp(param, "monitor-type")) {
1462 if (!strcasecmp(val, "mixmonitor"))
1464 } else if (!strcasecmp(param, "autopause")) {
1465 q->autopause = ast_true(val);
1466 } else if (!strcasecmp(param, "maxlen")) {
1467 q->maxlen = atoi(val);
1470 } else if (!strcasecmp(param, "servicelevel")) {
1471 q->servicelevel= atoi(val);
1472 } else if (!strcasecmp(param, "strategy")) {
1475 /* We are a static queue and already have set this, no need to do it again */
1479 strategy = strat2int(val);
1481 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
1483 q->strategy = QUEUE_STRATEGY_RINGALL;
1485 if (strategy == q->strategy) {
1488 if (strategy == QUEUE_STRATEGY_LINEAR) {
1489 ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n");
1492 q->strategy = strategy;
1493 } else if (!strcasecmp(param, "joinempty")) {
1494 parse_empty_options(val, &q->joinempty);
1495 } else if (!strcasecmp(param, "leavewhenempty")) {
1496 parse_empty_options(val, &q->leavewhenempty);
1497 } else if (!strcasecmp(param, "eventmemberstatus")) {
1498 q->maskmemberstatus = !ast_true(val);
1499 } else if (!strcasecmp(param, "eventwhencalled")) {
1500 if (!strcasecmp(val, "vars")) {
1501 q->eventwhencalled = QUEUE_EVENT_VARIABLES;
1503 q->eventwhencalled = ast_true(val) ? 1 : 0;
1505 } else if (!strcasecmp(param, "reportholdtime")) {
1506 q->reportholdtime = ast_true(val);
1507 } else if (!strcasecmp(param, "memberdelay")) {
1508 q->memberdelay = atoi(val);
1509 } else if (!strcasecmp(param, "weight")) {
1510 q->weight = atoi(val);
1513 /* With Realtime queues, if the last queue using weights is deleted in realtime,
1514 we will not see any effect on use_weight until next reload. */
1515 } else if (!strcasecmp(param, "timeoutrestart")) {
1516 q->timeoutrestart = ast_true(val);
1517 } else if (!strcasecmp(param, "defaultrule")) {
1518 ast_string_field_set(q, defaultrule, val);
1519 } else if (!strcasecmp(param, "timeoutpriority")) {
1520 if (!strcasecmp(val, "conf")) {
1521 q->timeoutpriority = TIMEOUT_PRIORITY_CONF;
1523 q->timeoutpriority = TIMEOUT_PRIORITY_APP;
1525 } else if (failunknown) {
1527 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
1528 q->name, param, linenum);
1530 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
1536 * \brief Find rt member record to update otherwise create one.
1538 * Search for member in queue, if found update penalty/paused state,
1539 * if no memeber exists create one flag it as a RT member and add to queue member list.
1541 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)
1544 struct ao2_iterator mem_iter;
1550 penalty = atoi(penalty_str);
1556 paused = atoi(paused_str);
1561 /* Find member by realtime uniqueid and update */
1562 mem_iter = ao2_iterator_init(q->members, 0);
1563 while ((m = ao2_iterator_next(&mem_iter))) {
1564 if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) {
1565 m->dead = 0; /* Do not delete this one. */
1566 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
1569 if (strcasecmp(state_interface, m->state_interface)) {
1570 ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
1572 m->penalty = penalty;
1580 /* Create a new member */
1582 if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) {
1585 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
1586 ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", "");
1587 ao2_link(q->members, m);
1595 /*! \brief Iterate through queue's member list and delete them */
1596 static void free_members(struct call_queue *q, int all)
1598 /* Free non-dynamic members */
1600 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
1602 while ((cur = ao2_iterator_next(&mem_iter))) {
1603 if (all || !cur->dynamic) {
1604 ao2_unlink(q->members, cur);
1611 /*! \brief Free queue's member list then its string fields */
1612 static void destroy_queue(void *obj)
1614 struct call_queue *q = obj;
1618 ast_string_field_free_memory(q);
1619 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
1620 if (q->sound_periodicannounce[i])
1621 free(q->sound_periodicannounce[i]);
1623 ao2_ref(q->members, -1);
1626 static struct call_queue *alloc_queue(const char *queuename)
1628 struct call_queue *q;
1630 if ((q = ao2_alloc(sizeof(*q), destroy_queue))) {
1631 if (ast_string_field_init(q, 64)) {
1635 ast_string_field_set(q, name, queuename);
1641 * \brief Reload a single queue via realtime.
1643 * Check for statically defined queue first, check if deleted RT queue,
1644 * check for new RT queue, if queue vars are not defined init them with defaults.
1645 * reload RT queue vars, set RT queue members dead and reload them, return finished queue.
1646 * \retval the queue,
1647 * \retval NULL if it doesn't exist.
1648 * \note Should be called with the "queues" container locked.
1650 static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
1652 struct ast_variable *v;
1653 struct call_queue *q, tmpq = {
1657 struct ao2_iterator mem_iter;
1658 char *interface = NULL;
1659 const char *tmp_name;
1661 char tmpbuf[64]; /* Must be longer than the longest queue param name. */
1663 /* Static queues override realtime. */
1664 if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
1672 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
1678 } else if (!member_config)
1679 /* Not found in the list, and it's not realtime ... */
1682 /* Check if queue is defined in realtime. */
1684 /* Delete queue from in-core list if it has been deleted in realtime. */
1686 /*! \note Hmm, can't seem to distinguish a DB failure from a not
1687 found condition... So we might delete an in-core queue
1688 in case of DB failure. */
1689 ast_debug(1, "Queue %s not found in realtime.\n", queuename);
1692 /* Delete if unused (else will be deleted when last caller leaves). */
1693 ao2_unlink(queues, q);
1700 /* Create a new queue if an in-core entry does not exist yet. */
1702 struct ast_variable *tmpvar = NULL;
1703 if (!(q = alloc_queue(queuename)))
1708 /*Before we initialize the queue, we need to set the strategy, so that linear strategy
1709 * will allocate the members properly
1711 for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) {
1712 if (!strcasecmp(tmpvar->name, "strategy")) {
1713 q->strategy = strat2int(tmpvar->value);
1714 if (q->strategy < 0) {
1715 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
1716 tmpvar->value, q->name);
1717 q->strategy = QUEUE_STRATEGY_RINGALL;
1722 /* We traversed all variables and didn't find a strategy */
1724 q->strategy = QUEUE_STRATEGY_RINGALL;
1725 ao2_link(queues, q);
1727 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
1729 memset(tmpbuf, 0, sizeof(tmpbuf));
1730 for (v = queue_vars; v; v = v->next) {
1731 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
1732 if ((tmp = strchr(v->name, '_'))) {
1733 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
1736 while ((tmp = strchr(tmp, '_')))
1741 if (!ast_strlen_zero(v->value)) {
1742 /* Don't want to try to set the option if the value is empty */
1743 queue_set_param(q, tmp_name, v->value, -1, 0);
1747 /* Temporarily set realtime members dead so we can detect deleted ones.
1748 * Also set the membercount correctly for realtime*/
1749 mem_iter = ao2_iterator_init(q->members, 0);
1750 while ((m = ao2_iterator_next(&mem_iter))) {
1757 while ((interface = ast_category_browse(member_config, interface))) {
1758 rt_handle_member_record(q, interface,
1759 ast_variable_retrieve(member_config, interface, "uniqueid"),
1760 S_OR(ast_variable_retrieve(member_config, interface, "membername"),interface),
1761 ast_variable_retrieve(member_config, interface, "penalty"),
1762 ast_variable_retrieve(member_config, interface, "paused"),
1763 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface));
1766 /* Delete all realtime members that have been deleted in DB. */
1767 mem_iter = ao2_iterator_init(q->members, 0);
1768 while ((m = ao2_iterator_next(&mem_iter))) {
1770 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
1771 ao2_unlink(q->members, m);
1782 static struct call_queue *load_realtime_queue(const char *queuename)
1784 struct ast_variable *queue_vars;
1785 struct ast_config *member_config = NULL;
1786 struct call_queue *q = NULL, tmpq = {
1790 /* Find the queue in the in-core list first. */
1791 q = ao2_find(queues, &tmpq, OBJ_POINTER);
1793 if (!q || q->realtime) {
1794 /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all
1795 queue operations while waiting for the DB.
1797 This will be two separate database transactions, so we might
1798 see queue parameters as they were before another process
1799 changed the queue and member list as it was after the change.
1800 Thus we might see an empty member list when a queue is
1801 deleted. In practise, this is unlikely to cause a problem. */
1803 queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL);
1805 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL);
1806 if (!member_config) {
1807 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
1808 ast_variables_destroy(queue_vars);
1814 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
1816 ast_config_destroy(member_config);
1818 ast_variables_destroy(queue_vars);
1822 update_realtime_members(q);
1827 static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
1831 if (ast_strlen_zero(mem->rt_uniqueid))
1834 if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) > 0)
1841 static void update_realtime_members(struct call_queue *q)
1843 struct ast_config *member_config = NULL;
1845 char *interface = NULL;
1846 struct ao2_iterator mem_iter;
1848 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , SENTINEL))) {
1849 /*This queue doesn't have realtime members*/
1850 ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name);
1857 /* Temporarily set realtime members dead so we can detect deleted ones.*/
1858 mem_iter = ao2_iterator_init(q->members, 0);
1859 while ((m = ao2_iterator_next(&mem_iter))) {
1865 while ((interface = ast_category_browse(member_config, interface))) {
1866 rt_handle_member_record(q, interface,
1867 ast_variable_retrieve(member_config, interface, "uniqueid"),
1868 S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
1869 ast_variable_retrieve(member_config, interface, "penalty"),
1870 ast_variable_retrieve(member_config, interface, "paused"),
1871 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface));
1874 /* Delete all realtime members that have been deleted in DB. */
1875 mem_iter = ao2_iterator_init(q->members, 0);
1876 while ((m = ao2_iterator_next(&mem_iter))) {
1878 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
1879 ao2_unlink(q->members, m);
1886 ast_config_destroy(member_config);
1889 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
1891 struct call_queue *q;
1892 struct queue_ent *cur, *prev = NULL;
1897 if (!(q = load_realtime_queue(queuename)))
1903 /* This is our one */
1906 if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, q->joinempty))) {
1907 *reason = QUEUE_JOINEMPTY;
1913 if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen))
1914 *reason = QUEUE_FULL;
1915 else if (*reason == QUEUE_UNKNOWN) {
1916 /* There's space for us, put us at the right position inside
1918 * Take into account the priority of the calling user */
1923 /* We have higher priority than the current user, enter
1924 * before him, after all the other users with priority
1925 * higher or equal to our priority. */
1926 if ((!inserted) && (qe->prio > cur->prio)) {
1927 insert_entry(q, prev, qe, &pos);
1934 /* No luck, join at the end of the queue */
1936 insert_entry(q, prev, qe, &pos);
1937 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
1938 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
1939 ast_copy_string(qe->context, q->context, sizeof(qe->context));
1942 manager_event(EVENT_FLAG_CALL, "Join",
1943 "Channel: %s\r\nCallerIDNum: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
1945 S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */
1946 S_OR(qe->chan->cid.cid_name, "unknown"),
1947 q->name, qe->pos, q->count, qe->chan->uniqueid );
1948 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
1956 static int play_file(struct ast_channel *chan, const char *filename)
1960 ast_stopstream(chan);
1962 res = ast_streamfile(chan, filename, chan->language);
1964 res = ast_waitstream(chan, AST_DIGIT_ANY);
1966 ast_stopstream(chan);
1972 * \brief Check for valid exit from queue via goto
1973 * \retval 0 if failure
1974 * \retval 1 if successful
1976 static int valid_exit(struct queue_ent *qe, char digit)
1978 int digitlen = strlen(qe->digits);
1980 /* Prevent possible buffer overflow */
1981 if (digitlen < sizeof(qe->digits) - 2) {
1982 qe->digits[digitlen] = digit;
1983 qe->digits[digitlen + 1] = '\0';
1985 qe->digits[0] = '\0';
1989 /* If there's no context to goto, short-circuit */
1990 if (ast_strlen_zero(qe->context))
1993 /* If the extension is bad, then reset the digits to blank */
1994 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) {
1995 qe->digits[0] = '\0';
1999 /* We have an exact match */
2000 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
2001 qe->valid_digits = 1;
2002 /* Return 1 on a successful goto */
2009 static int say_position(struct queue_ent *qe, int ringing)
2011 int res = 0, avgholdmins, avgholdsecs, announceposition = 0;
2014 /* Let minannouncefrequency seconds pass between the start of each position announcement */
2016 if ((now - qe->last_pos) < qe->parent->minannouncefrequency)
2019 /* If either our position has changed, or we are over the freq timer, say position */
2020 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency))
2024 ast_indicate(qe->chan,-1);
2026 ast_moh_stop(qe->chan);
2029 if (qe->parent->announceposition == ANNOUNCEPOSITION_YES ||
2030 qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN ||
2031 (qe->parent->announceposition == ANNOUNCEPOSITION_LIMIT &&
2032 qe->pos <= qe->parent->announcepositionlimit))
2033 announceposition = 1;
2036 if (announceposition == 1) {
2037 /* Say we're next, if we are */
2039 res = play_file(qe->chan, qe->parent->sound_next);
2045 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){
2047 res = play_file(qe->chan, qe->parent->queue_quantity1);
2050 res = ast_say_number(qe->chan, qe->parent->announcepositionlimit, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */
2055 res = play_file(qe->chan, qe->parent->sound_thereare);
2058 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */
2062 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){
2064 res = play_file(qe->chan, qe->parent->queue_quantity2);
2068 res = play_file(qe->chan, qe->parent->sound_calls);
2074 /* Round hold time to nearest minute */
2075 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
2077 /* If they have specified a rounding then round the seconds as well */
2078 if (qe->parent->roundingseconds) {
2079 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
2080 avgholdsecs *= qe->parent->roundingseconds;
2085 ast_verb(3, "Hold time for %s is %d minute(s) %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
2087 /* If the hold time is >1 min, if it's enabled, and if it's not
2088 supposed to be only once and we have already said it, say it */
2089 if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime &&
2090 ((qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE && !qe->last_pos) ||
2091 !(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE))) {
2092 res = play_file(qe->chan, qe->parent->sound_holdtime);
2096 if (avgholdmins > 1) {
2097 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL);
2101 if (avgholdmins == 1) {
2102 res = play_file(qe->chan, qe->parent->sound_minute);
2106 res = play_file(qe->chan, qe->parent->sound_minutes);
2111 if (avgholdsecs > 1) {
2112 res = ast_say_number(qe->chan, avgholdmins > 1 ? avgholdsecs : avgholdmins * 60 + avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL);
2116 res = play_file(qe->chan, qe->parent->sound_seconds);
2124 if (announceposition == 1){
2125 if (qe->parent->announceposition) {
2126 ast_verb(3, "Told %s in %s their queue position (which was %d)\n",
2127 qe->chan->name, qe->parent->name, qe->pos);
2129 res = play_file(qe->chan, qe->parent->sound_thanks);
2132 if ((res > 0 && !valid_exit(qe, res)) || res < 0)
2135 /* Set our last_pos indicators */
2137 qe->last_pos_said = qe->pos;
2139 /* Don't restart music on hold if we're about to exit the caller from the queue */
2142 ast_indicate(qe->chan, AST_CONTROL_RINGING);
2144 ast_moh_start(qe->chan, qe->moh, NULL);
2150 static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
2154 /* Calculate holdtime using an exponential average */
2155 /* Thanks to SRT for this contribution */
2156 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
2158 ao2_lock(qe->parent);
2159 oldvalue = qe->parent->holdtime;
2160 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
2161 ao2_unlock(qe->parent);
2164 /*! \brief Caller leaving queue.
2166 * Search the queue to find the leaving client, if found remove from queue
2167 * create manager event, move others up the queue.
2169 static void leave_queue(struct queue_ent *qe)
2171 struct call_queue *q;
2172 struct queue_ent *current, *prev = NULL;
2173 struct penalty_rule *pr_iter;
2176 if (!(q = qe->parent))
2182 for (current = q->head; current; current = current->next) {
2183 if (current == qe) {
2186 /* Take us out of the queue */
2187 manager_event(EVENT_FLAG_CALL, "Leave",
2188 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nUniqueid: %s\r\n",
2189 qe->chan->name, q->name, q->count, qe->chan->uniqueid);
2190 ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
2191 /* Take us out of the queue */
2193 prev->next = current->next;
2195 q->head = current->next;
2196 /* Free penalty rules */
2197 while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list)))
2200 /* Renumber the people after us in the queue based on a new count */
2201 current->pos = ++pos;
2207 /*If the queue is a realtime queue, check to see if it's still defined in real time*/
2209 struct ast_variable *var;
2210 if (!(var = ast_load_realtime("queues", "name", q->name, SENTINEL))) {
2213 ast_variables_destroy(var);
2218 /* It's dead and nobody is in it, so kill it */
2219 ao2_unlink(queues, q);
2221 /* unref the explicit ref earlier in the function */
2225 /*! \brief Hang up a list of outgoing calls */
2226 static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception)
2228 struct callattempt *oo;
2231 /* If someone else answered the call we should indicate this in the CANCEL */
2232 /* Hangup any existing lines we have open */
2233 if (outgoing->chan && (outgoing->chan != exception)) {
2235 ast_set_flag(outgoing->chan, AST_FLAG_ANSWERED_ELSEWHERE);
2236 ast_hangup(outgoing->chan);
2239 outgoing = outgoing->q_next;
2241 ao2_ref(oo->member, -1);
2247 * \brief traverse all defined queues which have calls waiting and contain this member
2248 * \retval 0 if no other queue has precedence (higher weight)
2249 * \retval 1 if found
2251 static int compare_weight(struct call_queue *rq, struct member *member)
2253 struct call_queue *q;
2256 struct ao2_iterator queue_iter;
2258 /* q's lock and rq's lock already set by try_calling()
2259 * to solve deadlock */
2260 queue_iter = ao2_iterator_init(queues, 0);
2261 while ((q = ao2_iterator_next(&queue_iter))) {
2262 if (q == rq) { /* don't check myself, could deadlock */
2267 if (q->count && q->members) {
2268 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
2269 ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
2270 if (q->weight > rq->weight) {
2271 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);
2286 /*! \brief common hangup actions */
2287 static void do_hang(struct callattempt *o)
2290 ast_hangup(o->chan);
2294 /*! \brief convert "\n" to "\nVariable: " ready for manager to use */
2295 static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
2297 struct ast_str *buf = ast_str_thread_get(&global_app_buf, len + 1);
2300 if (pbx_builtin_serialize_variables(chan, &buf)) {
2303 /* convert "\n" to "\nVariable: " */
2304 strcpy(vars, "Variable: ");
2305 tmp = ast_str_buffer(buf);
2307 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) {
2310 if (tmp[i + 1] == '\0')
2312 if (tmp[i] == '\n') {
2316 ast_copy_string(&(vars[j]), "Variable: ", len - j);
2326 /* there are no channel variables; leave it blank */
2333 * \brief Part 2 of ring_one
2335 * Does error checking before attempting to request a channel and call a member.
2336 * This function is only called from ring_one().
2337 * Failure can occur if:
2340 * - Wrapup time not expired
2341 * - Priority by another queue
2343 * \retval 1 on success to reach a free agent
2344 * \retval 0 on failure to get agent.
2346 static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
2352 const char *macrocontext, *macroexten;
2354 /* on entry here, we know that tmp->chan == NULL */
2355 if ((tmp->lastqueue && tmp->lastqueue->wrapuptime && (time(NULL) - tmp->lastcall < tmp->lastqueue->wrapuptime)) ||
2356 (!tmp->lastqueue && qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime))) {
2357 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
2358 (tmp->lastqueue ? tmp->lastqueue->name : qe->parent->name), tmp->interface);
2360 ast_cdr_busy(qe->chan->cdr);
2361 tmp->stillgoing = 0;
2366 if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
2367 ast_debug(1, "%s in use, can't receive call\n", tmp->interface);
2369 ast_cdr_busy(qe->chan->cdr);
2370 tmp->stillgoing = 0;
2374 if (tmp->member->paused) {
2375 ast_debug(1, "%s paused, can't receive call\n", tmp->interface);
2377 ast_cdr_busy(qe->chan->cdr);
2378 tmp->stillgoing = 0;
2381 if (use_weight && compare_weight(qe->parent,tmp->member)) {
2382 ast_debug(1, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
2384 ast_cdr_busy(qe->chan->cdr);
2385 tmp->stillgoing = 0;
2390 ast_copy_string(tech, tmp->interface, sizeof(tech));
2391 if ((location = strchr(tech, '/')))
2396 /* Request the peer */
2397 tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
2398 if (!tmp->chan) { /* If we can't, just go on to the next call */
2400 ast_cdr_busy(qe->chan->cdr);
2401 tmp->stillgoing = 0;
2403 ao2_lock(qe->parent);
2404 update_status(qe->parent, tmp->member, ast_device_state(tmp->member->state_interface));
2405 qe->parent->rrpos++;
2407 ao2_unlock(qe->parent);
2413 tmp->chan->appl = "AppQueue";
2414 tmp->chan->data = "(Outgoing Line)";
2415 memset(&tmp->chan->whentohangup, 0, sizeof(tmp->chan->whentohangup));
2416 if (tmp->chan->cid.cid_num)
2417 ast_free(tmp->chan->cid.cid_num);
2418 tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num);
2419 if (tmp->chan->cid.cid_name)
2420 ast_free(tmp->chan->cid.cid_name);
2421 tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name);
2422 if (tmp->chan->cid.cid_ani)
2423 ast_free(tmp->chan->cid.cid_ani);
2424 tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani);
2426 /* Inherit specially named variables from parent channel */
2427 ast_channel_inherit_variables(qe->chan, tmp->chan);
2429 /* Presense of ADSI CPE on outgoing channel follows ours */
2430 tmp->chan->adsicpe = qe->chan->adsicpe;
2432 /* Inherit context and extension */
2433 ast_channel_lock(qe->chan);
2434 macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT");
2435 ast_string_field_set(tmp->chan, dialcontext, ast_strlen_zero(macrocontext) ? qe->chan->context : macrocontext);
2436 macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN");
2437 if (!ast_strlen_zero(macroexten))
2438 ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten));
2440 ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten));
2441 ast_channel_unlock(qe->chan);
2443 /* Place the call, but don't wait on the answer */
2444 if ((res = ast_call(tmp->chan, location, 0))) {
2445 /* Again, keep going even if there's an error */
2446 ast_debug(1, "ast call on peer returned %d\n", res);
2447 ast_verb(3, "Couldn't call %s\n", tmp->interface);
2450 update_status(qe->parent, tmp->member, ast_device_state(tmp->member->interface));
2452 } else if (qe->parent->eventwhencalled) {
2455 manager_event(EVENT_FLAG_AGENT, "AgentCalled",
2457 "AgentCalled: %s\r\n"
2459 "ChannelCalling: %s\r\n"
2460 "DestinationChannel: %s\r\n"
2461 "CallerIDNum: %s\r\n"
2462 "CallerIDName: %s\r\n"
2468 qe->parent->name, tmp->interface, tmp->member->membername, qe->chan->name, tmp->chan->name,
2469 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
2470 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
2471 qe->chan->context, qe->chan->exten, qe->chan->priority, qe->chan->uniqueid,
2472 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
2473 ast_verb(3, "Called %s\n", tmp->interface);
2476 update_status(qe->parent, tmp->member, ast_device_state(tmp->member->interface));
2480 /*! \brief find the entry with the best metric, or NULL */
2481 static struct callattempt *find_best(struct callattempt *outgoing)
2483 struct callattempt *best = NULL, *cur;
2485 for (cur = outgoing; cur; cur = cur->q_next) {
2486 if (cur->stillgoing && /* Not already done */
2487 !cur->chan && /* Isn't already going */
2488 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */
2497 * \brief Place a call to a queue member.
2499 * Once metrics have been calculated for each member, this function is used
2500 * to place a call to the appropriate member (or members). The low-level
2501 * channel-handling and error detection is handled in ring_entry
2503 * \retval 1 if a member was called successfully
2504 * \retval 0 otherwise
2506 static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
2511 struct callattempt *best = find_best(outgoing);
2513 ast_debug(1, "Nobody left to try ringing in queue\n");
2516 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
2517 struct callattempt *cur;
2518 /* Ring everyone who shares this best metric (for ringall) */
2519 for (cur = outgoing; cur; cur = cur->q_next) {
2520 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
2521 ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
2522 ret |= ring_entry(qe, cur, busies);
2526 /* Ring just the best channel */
2527 ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric);
2528 ret = ring_entry(qe, best, busies);
2531 /* If we have timed out, break out */
2532 if (qe->expire && (time(NULL) >= qe->expire)) {
2533 ast_debug(1, "Queue timed out while ringing members.\n");
2542 /*! \brief Search for best metric and add to Round Robbin queue */
2543 static int store_next_rr(struct queue_ent *qe, struct callattempt *outgoing)
2545 struct callattempt *best = find_best(outgoing);
2548 /* Ring just the best channel */
2549 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
2550 qe->parent->rrpos = best->metric % 1000;
2552 /* Just increment rrpos */
2553 if (qe->parent->wrapped) {
2554 /* No more channels, start over */
2555 qe->parent->rrpos = 0;
2557 /* Prioritize next entry */
2558 qe->parent->rrpos++;
2561 qe->parent->wrapped = 0;
2566 /*! \brief Search for best metric and add to Linear queue */
2567 static int store_next_lin(struct queue_ent *qe, struct callattempt *outgoing)
2569 struct callattempt *best = find_best(outgoing);
2572 /* Ring just the best channel */
2573 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
2574 qe->linpos = best->metric % 1000;
2576 /* Just increment rrpos */
2577 if (qe->linwrapped) {
2578 /* No more channels, start over */
2581 /* Prioritize next entry */
2590 /*! \brief Playback announcement to queued members if peroid has elapsed */
2591 static int say_periodic_announcement(struct queue_ent *qe, int ringing)
2596 /* Get the current time */
2599 /* Check to see if it is time to announce */
2600 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
2603 /* Stop the music on hold so we can play our own file */
2605 ast_indicate(qe->chan,-1);
2607 ast_moh_stop(qe->chan);
2609 ast_verb(3, "Playing periodic announcement\n");
2611 if (qe->parent->randomperiodicannounce) {
2612 qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce;
2613 } else if (qe->last_periodic_announce_sound >= qe->parent->numperiodicannounce ||
2614 ast_str_strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]) == 0) {
2615 qe->last_periodic_announce_sound = 0;
2618 /* play the announcement */
2619 res = play_file(qe->chan, ast_str_buffer(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]));
2621 if ((res > 0 && !valid_exit(qe, res)) || res < 0)
2624 /* Resume Music on Hold if the caller is going to stay in the queue */
2627 ast_indicate(qe->chan, AST_CONTROL_RINGING);
2629 ast_moh_start(qe->chan, qe->moh, NULL);
2632 /* update last_periodic_announce_time */
2633 qe->last_periodic_announce_time = now;
2635 /* Update the current periodic announcement to the next announcement */
2636 if (!qe->parent->randomperiodicannounce) {
2637 qe->last_periodic_announce_sound++;
2643 /*! \brief Record that a caller gave up on waiting in queue */
2644 static void record_abandoned(struct queue_ent *qe)
2646 ao2_lock(qe->parent);
2647 set_queue_variables(qe);
2648 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
2652 "OriginalPosition: %d\r\n"
2654 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start));
2656 qe->parent->callsabandoned++;
2657 ao2_unlock(qe->parent);
2660 /*! \brief RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. */
2661 static void rna(int rnatime, struct queue_ent *qe, char *interface, char *membername)
2663 ast_verb(3, "Nobody picked up in %d ms\n", rnatime);
2664 if (qe->parent->eventwhencalled) {
2667 manager_event(EVENT_FLAG_AGENT, "AgentRingNoAnswer",
2672 "MemberName: %s\r\n"
2681 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
2683 ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
2684 if (qe->parent->autopause) {
2685 if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) {
2686 ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name);
2688 ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
2694 #define AST_MAX_WATCHERS 256
2695 /*! \brief Wait for a member to answer the call
2697 * \param[in] qe the queue_ent corresponding to the caller in the queue
2698 * \param[in] outgoing the list of callattempts. Relevant ones will have their chan and stillgoing parameters non-zero
2699 * \param[in] to the amount of time (in milliseconds) to wait for a response
2700 * \param[out] digit if a user presses a digit to exit the queue, this is the digit the caller pressed
2701 * \param[in] prebusies number of busy members calculated prior to calling wait_for_answer
2702 * \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
2703 * \param[in] forwardsallowed used to detect if we should allow call forwarding, based on the 'i' option to Queue()
2705 static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
2707 const char *queue = qe->parent->name;
2708 struct callattempt *o, *start = NULL, *prev = NULL;
2710 int numbusies = prebusies;
2714 struct ast_frame *f;
2715 struct callattempt *peer = NULL;
2716 struct ast_channel *winner;
2717 struct ast_channel *in = qe->chan;
2719 char membername[80] = "";
2723 struct callattempt *epollo;
2726 starttime = (long) time(NULL);
2728 for (epollo = outgoing; epollo; epollo = epollo->q_next) {
2730 ast_poll_channel_add(in, epollo->chan);
2734 while (*to && !peer) {
2735 int numlines, retry, pos = 1;
2736 struct ast_channel *watchers[AST_MAX_WATCHERS];
2740 for (retry = 0; retry < 2; retry++) {
2742 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
2743 if (o->stillgoing) { /* Keep track of important channels */
2746 watchers[pos++] = o->chan;
2750 prev->call_next = o;
2756 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
2757 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */)
2759 /* On "ringall" strategy we only move to the next penalty level
2760 when *all* ringing phones are done in the current penalty level */
2761 ring_one(qe, outgoing, &numbusies);
2764 if (pos == 1 /* not found */) {
2765 if (numlines == (numbusies + numnochan)) {
2766 ast_debug(1, "Everyone is busy at this time\n");
2768 ast_debug(3, "No one is answering queue '%s' (%d numlines / %d busies / %d failed channels)\n", queue, numlines, numbusies, numnochan);
2773 winner = ast_waitfor_n(watchers, pos, to);
2774 for (o = start; o; o = o->call_next) {
2775 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
2777 ast_verb(3, "%s answered %s\n", o->chan->name, in->name);
2780 } else if (o->chan && (o->chan == winner)) {
2782 ast_copy_string(on, o->member->interface, sizeof(on));
2783 ast_copy_string(membername, o->member->membername, sizeof(membername));
2785 if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) {
2786 ast_verb(3, "Forwarding %s to '%s' prevented.\n", in->name, o->chan->call_forward);
2791 } else if (!ast_strlen_zero(o->chan->call_forward)) {
2796 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
2797 if ((stuff = strchr(tmpchan, '/'))) {
2801 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
2805 /* Before processing channel, go ahead and check for forwarding */
2806 ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
2807 /* Setup parameters */
2808 o->chan = ast_request(tech, in->nativeformats, stuff, &status);
2810 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
2814 ast_channel_inherit_variables(in, o->chan);
2815 ast_channel_datastore_inherit(in, o->chan);
2816 if (o->chan->cid.cid_num)
2817 ast_free(o->chan->cid.cid_num);
2818 o->chan->cid.cid_num = ast_strdup(in->cid.cid_num);
2820 if (o->chan->cid.cid_name)
2821 ast_free(o->chan->cid.cid_name);
2822 o->chan->cid.cid_name = ast_strdup(in->cid.cid_name);
2824 ast_string_field_set(o->chan, accountcode, in->accountcode);
2825 o->chan->cdrflags = in->cdrflags;
2827 if (in->cid.cid_ani) {
2828 if (o->chan->cid.cid_ani)
2829 ast_free(o->chan->cid.cid_ani);
2830 o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani);
2832 if (o->chan->cid.cid_rdnis)
2833 ast_free(o->chan->cid.cid_rdnis);
2834 o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten));
2835 if (ast_call(o->chan, tmpchan, 0)) {
2836 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
2841 /* Hangup the original channel now, in case we needed it */
2845 f = ast_read(winner);
2847 if (f->frametype == AST_FRAME_CONTROL) {
2848 switch (f->subclass) {
2849 case AST_CONTROL_ANSWER:
2850 /* This is our guy if someone answered. */
2852 ast_verb(3, "%s answered %s\n", o->chan->name, in->name);
2856 case AST_CONTROL_BUSY:
2857 ast_verb(3, "%s is busy\n", o->chan->name);
2859 ast_cdr_busy(in->cdr);
2861 endtime = (long) time(NULL);
2862 endtime -= starttime;
2863 rna(endtime*1000, qe, on, membername);
2864 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2865 if (qe->parent->timeoutrestart)
2867 ring_one(qe, outgoing, &numbusies);
2871 case AST_CONTROL_CONGESTION:
2872 ast_verb(3, "%s is circuit-busy\n", o->chan->name);
2874 ast_cdr_busy(in->cdr);
2875 endtime = (long) time(NULL);
2876 endtime -= starttime;
2877 rna(endtime*1000, qe, on, membername);
2879 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2880 if (qe->parent->timeoutrestart)
2882 ring_one(qe, outgoing, &numbusies);
2886 case AST_CONTROL_RINGING:
2887 ast_verb(3, "%s is ringing\n", o->chan->name);
2889 case AST_CONTROL_OFFHOOK:
2890 /* Ignore going off hook */
2893 ast_debug(1, "Dunno what to do with control type %d\n", f->subclass);
2898 endtime = (long) time(NULL) - starttime;
2899 rna(endtime * 1000, qe, on, membername);
2901 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2902 if (qe->parent->timeoutrestart)
2904 ring_one(qe, outgoing, &numbusies);
2911 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
2915 if (f->data.uint32) {
2916 in->hangupcause = f->data.uint32;
2922 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) {
2923 ast_verb(3, "User hit %c to disconnect call.\n", f->subclass);
2928 if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass)) {
2929 ast_verb(3, "User pressed digit: %c\n", f->subclass);
2931 *digit = f->subclass;
2938 for (o = start; o; o = o->call_next)
2939 rna(orig, qe, o->interface, o->member->membername);
2944 for (epollo = outgoing; epollo; epollo = epollo->q_next) {
2946 ast_poll_channel_del(in, epollo->chan);
2954 * \brief Check if we should start attempting to call queue members.
2956 * The behavior of this function is dependent first on whether autofill is enabled
2957 * and second on whether the ring strategy is ringall. If autofill is not enabled,
2958 * then return true if we're the head of the queue. If autofill is enabled, then
2959 * we count the available members and see if the number of available members is enough
2960 * that given our position in the queue, we would theoretically be able to connect to
2961 * one of those available members
2963 static int is_our_turn(struct queue_ent *qe)
2965 struct queue_ent *ch;
2971 if (!qe->parent->autofill) {
2972 /* Atomically read the parent head -- does not need a lock */
2973 ch = qe->parent->head;
2974 /* If we are now at the top of the head, break out */
2976 ast_debug(1, "It's our turn (%s).\n", qe->chan->name);
2979 ast_debug(1, "It's not our turn (%s).\n", qe->chan->name);
2984 /* This needs a lock. How many members are available to be served? */
2985 ao2_lock(qe->parent);
2987 ch = qe->parent->head;
2989 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
2990 ast_debug(1, "Even though there may be multiple members available, the strategy is ringall so only the head call is allowed in\n");
2993 struct ao2_iterator mem_iter = ao2_iterator_init(qe->parent->members, 0);
2994 while ((cur = ao2_iterator_next(&mem_iter))) {
2995 switch (cur->status) {
2996 case AST_DEVICE_INUSE:
2997 if (!qe->parent->ringinuse)
2999 /* else fall through */
3000 case AST_DEVICE_NOT_INUSE:
3001 case AST_DEVICE_UNKNOWN:
3010 ast_debug(1, "There are %d available members.\n", avl);
3012 while ((idx < avl) && (ch) && (ch != qe)) {
3018 /* If the queue entry is within avl [the number of available members] calls from the top ... */
3019 if (ch && idx < avl) {
3020 ast_debug(1, "It's our turn (%s).\n", qe->chan->name);
3023 ast_debug(1, "It's not our turn (%s).\n", qe->chan->name);
3027 ao2_unlock(qe->parent);
3034 * \brief update rules for queues
3036 * Calculate min/max penalties making sure if relative they stay within bounds.
3037 * Update queues penalty and set dialplan vars, goto next list entry.
3039 static void update_qe_rule(struct queue_ent *qe)
3041 int max_penalty = qe->pr->max_relative ? qe->max_penalty + qe->pr->max_value : qe->pr->max_value;
3042 int min_penalty = qe->pr->min_relative ? qe->min_penalty + qe->pr->min_value : qe->pr->min_value;
3043 char max_penalty_str[20], min_penalty_str[20];
3044 /* a relative change to the penalty could put it below 0 */
3045 if (max_penalty < 0)
3047 if (min_penalty < 0)
3049 if (min_penalty > max_penalty)
3050 min_penalty = max_penalty;
3051 snprintf(max_penalty_str, sizeof(max_penalty_str), "%d", max_penalty);
3052 snprintf(min_penalty_str, sizeof(min_penalty_str), "%d", min_penalty);
3053 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MAX_PENALTY", max_penalty_str);
3054 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MIN_PENALTY", min_penalty_str);
3055 qe->max_penalty = max_penalty;
3056 qe->min_penalty = min_penalty;
3057 ast_debug(3, "Setting max penalty to %d and min penalty to %d for caller %s since %d seconds have elapsed\n", qe->max_penalty, qe->min_penalty, qe->chan->name, qe->pr->time);
3058 qe->pr = AST_LIST_NEXT(qe->pr, list);
3061 /*! \brief The waiting areas for callers who are not actively calling members
3063 * This function is one large loop. This function will return if a caller
3064 * either exits the queue or it becomes that caller's turn to attempt calling
3065 * queue members. Inside the loop, we service the caller with periodic announcements,
3066 * holdtime announcements, etc. as configured in queues.conf
3068 * \retval 0 if the caller's turn has arrived
3069 * \retval -1 if the caller should exit the queue.
3071 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
3075 /* This is the holding pen for callers 2 through maxlen */
3078 if (is_our_turn(qe))
3081 /* If we have timed out, break out */
3082 if (qe->expire && (time(NULL) >= qe->expire)) {
3083 *reason = QUEUE_TIMEOUT;
3087 if (qe->parent->leavewhenempty) {
3090 if ((status = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty, qe->parent->leavewhenempty))) {
3091 *reason = QUEUE_LEAVEEMPTY;
3092 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
3098 /* Make a position announcement, if enabled */
3099 if (qe->parent->announcefrequency &&
3100 (res = say_position(qe,ringing)))
3103 /* If we have timed out, break out */
3104 if (qe->expire && (time(NULL) >= qe->expire)) {
3105 *reason = QUEUE_TIMEOUT;
3109 /* Make a periodic announcement, if enabled */
3110 if (qe->parent->periodicannouncefrequency &&
3111 (res = say_periodic_announcement(qe,ringing)))
3114 /* see if we need to move to the next penalty level for this queue */
3115 while (qe->pr && ((time(NULL) - qe->start) >= qe->pr->time)) {
3119 /* If we have timed out, break out */
3120 if (qe->expire && (time(NULL) >= qe->expire)) {
3121 *reason = QUEUE_TIMEOUT;
3125 /* Wait a second before checking again */
3126 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
3127 if (res > 0 && !valid_exit(qe, res))
3133 /* If we have timed out, break out */
3134 if (qe->expire && (time(NULL) >= qe->expire)) {
3135 *reason = QUEUE_TIMEOUT;
3144 * \brief update the queue status
3147 static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, int newtalktime)
3152 struct call_queue *qtmp;
3153 struct ao2_iterator queue_iter;
3155 if (shared_lastcall) {
3156 queue_iter = ao2_iterator_init(queues, 0);
3157 while ((qtmp = ao2_iterator_next(&queue_iter))) {
3159 if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) {
3160 time(&mem->lastcall);
3170 time(&member->lastcall);
3172 member->lastqueue = q;
3176 q->callscompleted++;
3177 if (callcompletedinsl)
3178 q->callscompletedinsl++;
3179 /* Calculate talktime using the same exponential average as holdtime code*/
3180 oldtalktime = q->talktime;
3181 q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
3186 /*! \brief Calculate the metric of each member in the outgoing callattempts
3188 * A numeric metric is given to each member depending on the ring strategy used
3189 * by the queue. Members with lower metrics will be called before members with
3191 * \retval -1 if penalties are exceeded
3192 * \retval 0 otherwise
3194 static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
3196 if ((qe->max_penalty && (mem->penalty > qe->max_penalty)) || (qe->min_penalty && (mem->penalty < qe->min_penalty)))
3199 switch (q->strategy) {
3200 case QUEUE_STRATEGY_RINGALL:
3201 /* Everyone equal, except for penalty */
3202 tmp->metric = mem->penalty * 1000000;
3204 case QUEUE_STRATEGY_LINEAR:
3205 if (pos < qe->linpos) {
3206 tmp->metric = 1000 + pos;
3208 if (pos > qe->linpos)
3209 /* Indicate there is another priority */
3213 tmp->metric += mem->penalty * 1000000;
3215 case QUEUE_STRATEGY_RRMEMORY:
3216 if (pos < q->rrpos) {
3217 tmp->metric = 1000 + pos;
3220 /* Indicate there is another priority */
3224 tmp->metric += mem->penalty * 1000000;
3226 case QUEUE_STRATEGY_RANDOM:
3227 tmp->metric = ast_random() % 1000;
3228 tmp->metric += mem->penalty * 1000000;
3230 case QUEUE_STRATEGY_WRANDOM:
3231 tmp->metric = ast_random() % ((1 + mem->penalty) * 1000);
3233 case QUEUE_STRATEGY_FEWESTCALLS:
3234 tmp->metric = mem->calls;
3235 tmp->metric += mem->penalty * 1000000;
3237 case QUEUE_STRATEGY_LEASTRECENT:
3241 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
3242 tmp->metric += mem->penalty * 1000000;
3245 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
3251 enum agent_complete_reason {
3257 /*! \brief Send out AMI message with member call completion status information */
3258 static void send_agent_complete(const struct queue_ent *qe, const char *queuename,
3259 const struct ast_channel *peer, const struct member *member, time_t callstart,
3260 char *vars, size_t vars_len, enum agent_complete_reason rsn)
3262 const char *reason = NULL; /* silence dumb compilers */
3264 if (!qe->parent->eventwhencalled)
3275 reason = "transfer";
3279 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
3284 "MemberName: %s\r\n"
3289 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
3290 (long)(callstart - qe->start), (long)(time(NULL) - callstart), reason,
3291 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : "");
3294 struct queue_transfer_ds {
3295 struct queue_ent *qe;
3296 struct member *member;
3298 int callcompletedinsl;
3301 static void queue_transfer_destroy(void *data)
3303 struct queue_transfer_ds *qtds = data;
3307 /*! \brief a datastore used to help correctly log attended transfers of queue callers
3309 static const struct ast_datastore_info queue_transfer_info = {
3310 .type = "queue_transfer",
3311 .chan_fixup = queue_transfer_fixup,
3312 .destroy = queue_transfer_destroy,
3315 /*! \brief Log an attended transfer when a queue caller channel is masqueraded
3317 * When a caller is masqueraded, we want to log a transfer. Fixup time is the closest we can come to when