Asterisk - The Open Source Telephony Project GIT-master-3dee037
app_queue.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2018, Digium, Inc.
5 *
6 * Mark Spencer <markster@digium.com>
7 *
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.
13 *
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.
17 */
18
19/*! \file
20 *
21 * \brief True call queues with optional send URL on answer
22 *
23 * \author Mark Spencer <markster@digium.com>
24 *
25 * \par Development notes
26 * \note 2004-11-25: Persistent Dynamic Members added by:
27 * NetNation Communications (www.netnation.com)
28 * Kevin Lindsay <kevinl@netnation.com>
29 *
30 * Each dynamic agent in each queue is now stored in the astdb.
31 * When asterisk is restarted, each agent will be automatically
32 * readded into their recorded queues. This feature can be
33 * configured with the 'persistent_members=<1|0>' setting in the
34 * '[general]' category in queues.conf. The default is on.
35 *
36 * \note 2004-06-04: Priorities in queues added by inAccess Networks (work funded by Hellas On Line (HOL) www.hol.gr).
37 *
38 * \note These features added by David C. Troy <dave@toad.net>:
39 * - Per-queue holdtime calculation
40 * - Estimated holdtime announcement
41 * - Position announcement
42 * - Abandoned/completed call counters
43 * - Failout timer passed as optional app parameter
44 *
45 * Patch Version 1.07 2003-12-24 01
46 *
47 * Added servicelevel statistic by Michiel Betel <michiel@betel.nl>
48 * Added Priority jumping code for adding and removing queue members by Jonathan Stanton <asterisk@doilooklikeicare.com>
49 *
50 * Fixed to work with CVS as of 2004-02-25 and released as 1.07a
51 * by Matthew Enger <m.enger@xi.com.au>
52 *
53 * \ingroup applications
54 */
55
56/*! \li \ref app_queues.c uses configuration file \ref queues.conf
57 * \addtogroup configuration_file
58 */
59
60/*! \page queues.conf queues.conf
61 * \verbinclude queues.conf.sample
62 */
63
64/*** MODULEINFO
65 <support_level>core</support_level>
66 ***/
67
68#include "asterisk.h"
69
70#include <sys/time.h>
71#include <signal.h>
72#include <netinet/in.h>
73#include <ctype.h>
74
75#include "asterisk/lock.h"
76#include "asterisk/file.h"
77#include "asterisk/channel.h"
78#include "asterisk/pbx.h"
79#include "asterisk/app.h"
81#include "asterisk/module.h"
82#include "asterisk/translate.h"
83#include "asterisk/say.h"
84#include "asterisk/features.h"
86#include "asterisk/cli.h"
87#include "asterisk/manager.h"
88#include "asterisk/config.h"
89#include "asterisk/utils.h"
90#include "asterisk/causes.h"
91#include "asterisk/astdb.h"
94#include "asterisk/astobj2.h"
95#include "asterisk/strings.h"
97#include "asterisk/aoc.h"
98#include "asterisk/callerid.h"
99#include "asterisk/term.h"
100#include "asterisk/dial.h"
105#include "asterisk/core_local.h"
106#include "asterisk/mixmonitor.h"
109
110/*!
111 * \par Please read before modifying this file.
112 * There are three locks which are regularly used
113 * throughout this file, the queue list lock, the lock
114 * for each individual queue, and the interface list lock.
115 * Please be extra careful to always lock in the following order
116 * 1) queue list lock
117 * 2) individual queue lock
118 * 3) interface list lock
119 * This order has sort of "evolved" over the lifetime of this
120 * application, but it is now in place this way, so please adhere
121 * to this order!
122 */
123
124/*** DOCUMENTATION
125 <application name="Queue" language="en_US">
126 <synopsis>
127 Queue a call for a call queue.
128 </synopsis>
129 <syntax>
130 <parameter name="queuename" required="true" />
131 <parameter name="options">
132 <optionlist>
133 <option name="b" argsep="^">
134 <para>Before initiating an outgoing call, <literal>Gosub</literal> to the specified
135 location using the newly created channel. The <literal>Gosub</literal> will be
136 executed for each destination channel.</para>
137 <argument name="context" required="false" />
138 <argument name="exten" required="false" />
139 <argument name="priority" required="true" hasparams="optional" argsep="^">
140 <argument name="arg1" multiple="true" required="true" />
141 <argument name="argN" />
142 </argument>
143 </option>
144 <option name="B" argsep="^">
145 <para>Before initiating the outgoing call(s), <literal>Gosub</literal> to the
146 specified location using the current channel.</para>
147 <argument name="context" required="false" />
148 <argument name="exten" required="false" />
149 <argument name="priority" required="true" hasparams="optional" argsep="^">
150 <argument name="arg1" multiple="true" required="true" />
151 <argument name="argN" />
152 </argument>
153 </option>
154 <option name="C">
155 <para>Mark all calls as "answered elsewhere" when cancelled.</para>
156 </option>
157 <option name="c">
158 <para>Continue in the dialplan if the callee hangs up.</para>
159 </option>
160 <option name="d">
161 <para>Data-quality (modem) call (minimum delay).</para>
162 <para>This option only applies to DAHDI channels. By default,
163 DTMF is verified by muting audio TX/RX to verify the tone
164 is still present. This option disables that behavior.</para>
165 </option>
166 <option name="F" argsep="^">
167 <argument name="context" required="false" />
168 <argument name="exten" required="false" />
169 <argument name="priority" required="true" />
170 <para>When the caller hangs up, transfer the <emphasis>called member</emphasis>
171 to the specified destination and <emphasis>start</emphasis> execution at that location.</para>
172 <para>NOTE: Any channel variables you want the called channel to inherit from the caller channel must be
173 prefixed with one or two underbars ('_').</para>
174 <para>NOTE: Using this option from a GoSub() might not make sense as there would be no return points.</para>
175 </option>
176 <option name="h">
177 <para>Allow <emphasis>callee</emphasis> to hang up by pressing <literal>*</literal>.</para>
178 </option>
179 <option name="H">
180 <para>Allow <emphasis>caller</emphasis> to hang up by pressing <literal>*</literal>.</para>
181 </option>
182 <option name="i">
183 <para>Ignore call forward requests from queue members and do nothing
184 when they are requested.</para>
185 </option>
186 <option name="I">
187 <para>Asterisk will ignore any connected line update requests or any redirecting party
188 update requests it may receive on this dial attempt.</para>
189 </option>
190 <option name="k">
191 <para>Allow the <emphasis>called</emphasis> party to enable parking of the call by sending
192 the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
193 </option>
194 <option name="K">
195 <para>Allow the <emphasis>calling</emphasis> party to enable parking of the call by sending
196 the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
197 </option>
198 <option name="m">
199 <para>Custom music on hold class to use, which will override the music on hold class configured
200 in <filename>queues.conf</filename>, if specified.</para>
201 <para>Note that CHANNEL(musicclass), if set, will still override this option.</para>
202 </option>
203 <option name="n">
204 <para>No retries on the timeout; will exit this application and
205 go to the next step.</para>
206 </option>
207 <option name="r">
208 <para>Ring instead of playing MOH. Periodic Announcements are still made, if applicable.</para>
209 </option>
210 <option name="R">
211 <para>Ring instead of playing MOH when a member channel is actually ringing.</para>
212 </option>
213 <option name="t">
214 <para>Allow the <emphasis>called</emphasis> user to transfer the calling user.</para>
215 </option>
216 <option name="T">
217 <para>Allow the <emphasis>calling</emphasis> user to transfer the call.</para>
218 </option>
219 <option name="x">
220 <para>Allow the <emphasis>called</emphasis> user to write the conversation
221 to disk via MixMonitor.</para>
222 </option>
223 <option name="X">
224 <para>Allow the <emphasis>calling</emphasis> user to write the conversation to
225 disk via MixMonitor.</para>
226 </option>
227 </optionlist>
228 </parameter>
229 <parameter name="URL">
230 <para><replaceable>URL</replaceable> will be sent to the called party if the channel supports it.</para>
231 </parameter>
232 <parameter name="announceoverride" argsep="&amp;">
233 <para>Announcement file(s) to play to agent before bridging
234 call, overriding the announcement(s) configured in
235 <filename>queues.conf</filename>, if any.</para>
236 <para>Ampersand separated list of filenames. If the filename
237 is a relative filename (it does not begin with a slash), it
238 will be searched for in the Asterisk sounds directory. If the
239 filename is able to be parsed as a URL, Asterisk will
240 download the file and then begin playback on it. To include a
241 literal <literal>&amp;</literal> in the URL you can enclose
242 the URL in single quotes.</para>
243 <argument name="announceoverride" required="true" />
244 <argument name="announceoverride2" multiple="true" />
245 </parameter>
246 <parameter name="timeout">
247 <para>Will cause the queue to fail out after a specified number of
248 seconds, checked between each <filename>queues.conf</filename> <replaceable>timeout</replaceable> and
249 <replaceable>retry</replaceable> cycle.</para>
250 </parameter>
251 <parameter name="AGI">
252 <para>Will setup an AGI script to be executed on the calling party's channel once they are
253 connected to a queue member.</para>
254 </parameter>
255 <parameter name="gosub">
256 <para>Will run a gosub on the called party's channel (the queue member)
257 once the parties are connected. The subroutine execution starts in the
258 named context at the s exten and priority 1.</para>
259 </parameter>
260 <parameter name="rule">
261 <para>Will cause the queue's defaultrule to be overridden by the rule specified.</para>
262 </parameter>
263 <parameter name="position">
264 <para>Attempt to enter the caller into the queue at the numerical position specified. <literal>1</literal>
265 would attempt to enter the caller at the head of the queue, and <literal>3</literal> would attempt to place
266 the caller third in the queue.</para>
267 </parameter>
268 </syntax>
269 <description>
270 <para>In addition to transferring the call, a call may be parked and then picked
271 up by another user.</para>
272 <para>This application will return to the dialplan if the queue does not exist, or
273 any of the join options cause the caller to not enter the queue.</para>
274 <para>This application does not automatically answer and should be preceeded
275 by an application such as Answer(), Progress(), or Ringing().</para>
276 <para>This application sets the following channel variables upon completion:</para>
277 <variablelist>
278 <variable name="QUEUESTATUS">
279 <para>The status of the call as a text string.</para>
280 <value name="TIMEOUT" />
281 <value name="FULL" />
282 <value name="JOINEMPTY" />
283 <value name="LEAVEEMPTY" />
284 <value name="JOINUNAVAIL" />
285 <value name="LEAVEUNAVAIL" />
286 <value name="CONTINUE" />
287 <value name="WITHDRAW" />
288 </variable>
289 <variable name="ABANDONED">
290 <para>If the call was not answered by an agent this variable will be TRUE.</para>
291 <value name="TRUE" />
292 </variable>
293 <variable name="DIALEDPEERNUMBER">
294 <para>Resource of the agent that was dialed set on the outbound channel.</para>
295 </variable>
296 <variable name="QUEUE_WITHDRAW_INFO">
297 <para>If the call was successfully withdrawn from the queue, and the withdraw request was provided with optional withdraw info, the withdraw info will be stored in this variable.</para>
298 </variable>
299 </variablelist>
300 </description>
301 <see-also>
302 <ref type="application">Queue</ref>
303 <ref type="application">QueueLog</ref>
304 <ref type="application">AddQueueMember</ref>
305 <ref type="application">RemoveQueueMember</ref>
306 <ref type="application">PauseQueueMember</ref>
307 <ref type="application">UnpauseQueueMember</ref>
308 <ref type="function">QUEUE_VARIABLES</ref>
309 <ref type="function">QUEUE_MEMBER</ref>
310 <ref type="function">QUEUE_MEMBER_COUNT</ref>
311 <ref type="function">QUEUE_EXISTS</ref>
312 <ref type="function">QUEUE_GET_CHANNEL</ref>
313 <ref type="function">QUEUE_WAITING_COUNT</ref>
314 <ref type="function">QUEUE_MEMBER_LIST</ref>
315 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
316 </see-also>
317 </application>
318 <application name="AddQueueMember" language="en_US">
319 <synopsis>
320 Dynamically adds queue members.
321 </synopsis>
322 <syntax>
323 <parameter name="queuename" required="true" />
324 <parameter name="interface" />
325 <parameter name="penalty" />
326 <parameter name="options">
327 <optionlist>
328 <option name="p">
329 <para>Add queue member in paused state.</para>
330 </option>
331 <option name="r">
332 <argument name="reason" required="true" />
333 <para>Specify a reason why the member is in paused state.</para>
334 </option>
335 </optionlist>
336 </parameter>
337 <parameter name="membername" />
338 <parameter name="stateinterface" />
339 <parameter name="wrapuptime" />
340 </syntax>
341 <description>
342 <para>Dynamically adds interface to an existing queue. If the interface is
343 already in the queue it will return an error.</para>
344 <para>This application sets the following channel variable upon completion:</para>
345 <variablelist>
346 <variable name="AQMSTATUS">
347 <para>The status of the attempt to add a queue member as a text string.</para>
348 <value name="ADDED" />
349 <value name="MEMBERALREADY" />
350 <value name="NOSUCHQUEUE" />
351 </variable>
352 </variablelist>
353 </description>
354 <see-also>
355 <ref type="application">Queue</ref>
356 <ref type="application">QueueLog</ref>
357 <ref type="application">AddQueueMember</ref>
358 <ref type="application">RemoveQueueMember</ref>
359 <ref type="application">PauseQueueMember</ref>
360 <ref type="application">UnpauseQueueMember</ref>
361 <ref type="function">QUEUE_VARIABLES</ref>
362 <ref type="function">QUEUE_MEMBER</ref>
363 <ref type="function">QUEUE_MEMBER_COUNT</ref>
364 <ref type="function">QUEUE_EXISTS</ref>
365 <ref type="function">QUEUE_GET_CHANNEL</ref>
366 <ref type="function">QUEUE_WAITING_COUNT</ref>
367 <ref type="function">QUEUE_MEMBER_LIST</ref>
368 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
369 </see-also>
370 </application>
371 <application name="RemoveQueueMember" language="en_US">
372 <synopsis>
373 Dynamically removes queue members.
374 </synopsis>
375 <syntax>
376 <parameter name="queuename" required="true" />
377 <parameter name="interface" />
378 </syntax>
379 <description>
380 <para>If the interface is <emphasis>NOT</emphasis> in the queue it will return an error.</para>
381 <para>This application sets the following channel variable upon completion:</para>
382 <variablelist>
383 <variable name="RQMSTATUS">
384 <value name="REMOVED" />
385 <value name="NOTINQUEUE" />
386 <value name="NOSUCHQUEUE" />
387 <value name="NOTDYNAMIC" />
388 </variable>
389 </variablelist>
390 <example title="Remove queue member">
391 same => n,RemoveQueueMember(techsupport,SIP/3000)
392 </example>
393 </description>
394 <see-also>
395 <ref type="application">Queue</ref>
396 <ref type="application">QueueLog</ref>
397 <ref type="application">AddQueueMember</ref>
398 <ref type="application">RemoveQueueMember</ref>
399 <ref type="application">PauseQueueMember</ref>
400 <ref type="application">UnpauseQueueMember</ref>
401 <ref type="function">QUEUE_VARIABLES</ref>
402 <ref type="function">QUEUE_MEMBER</ref>
403 <ref type="function">QUEUE_MEMBER_COUNT</ref>
404 <ref type="function">QUEUE_EXISTS</ref>
405 <ref type="function">QUEUE_GET_CHANNEL</ref>
406 <ref type="function">QUEUE_WAITING_COUNT</ref>
407 <ref type="function">QUEUE_MEMBER_LIST</ref>
408 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
409 </see-also>
410 </application>
411 <application name="PauseQueueMember" language="en_US">
412 <synopsis>
413 Pauses a queue member.
414 </synopsis>
415 <syntax>
416 <parameter name="queuename" />
417 <parameter name="interface" required="true" />
418 <parameter name="options" />
419 <parameter name="reason">
420 <para>Is used to add extra information to the appropriate queue_log entries and manager events.</para>
421 </parameter>
422 </syntax>
423 <description>
424 <para>Pauses (blocks calls for) a queue member. The given interface will be paused in the given queue.
425 This prevents any calls from being sent from the queue to the interface until it is
426 unpaused with UnpauseQueueMember or the manager interface. If no queuename is given,
427 the interface is paused in every queue it is a member of. The application will fail if the
428 interface is not found.</para>
429 <para>This application sets the following channel variable upon completion:</para>
430 <variablelist>
431 <variable name="PQMSTATUS">
432 <para>The status of the attempt to pause a queue member as a text string.</para>
433 <value name="PAUSED" />
434 <value name="NOTFOUND" />
435 </variable>
436 </variablelist>
437 <example title="Pause queue member">
438 same => n,PauseQueueMember(,SIP/3000)
439 </example>
440 </description>
441 <see-also>
442 <ref type="application">Queue</ref>
443 <ref type="application">QueueLog</ref>
444 <ref type="application">AddQueueMember</ref>
445 <ref type="application">RemoveQueueMember</ref>
446 <ref type="application">PauseQueueMember</ref>
447 <ref type="application">UnpauseQueueMember</ref>
448 <ref type="function">QUEUE_VARIABLES</ref>
449 <ref type="function">QUEUE_MEMBER</ref>
450 <ref type="function">QUEUE_MEMBER_COUNT</ref>
451 <ref type="function">QUEUE_EXISTS</ref>
452 <ref type="function">QUEUE_GET_CHANNEL</ref>
453 <ref type="function">QUEUE_WAITING_COUNT</ref>
454 <ref type="function">QUEUE_MEMBER_LIST</ref>
455 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
456 </see-also>
457 </application>
458 <application name="UnpauseQueueMember" language="en_US">
459 <synopsis>
460 Unpauses a queue member.
461 </synopsis>
462 <syntax>
463 <parameter name="queuename" />
464 <parameter name="interface" required="true" />
465 <parameter name="options" />
466 <parameter name="reason">
467 <para>Is used to add extra information to the appropriate queue_log entries and manager events.</para>
468 </parameter>
469 </syntax>
470 <description>
471 <para>Unpauses (resumes calls to) a queue member. This is the counterpart to <literal>PauseQueueMember()</literal>
472 and operates exactly the same way, except it unpauses instead of pausing the given interface.</para>
473 <para>This application sets the following channel variable upon completion:</para>
474 <variablelist>
475 <variable name="UPQMSTATUS">
476 <para>The status of the attempt to unpause a queue member as a text string.</para>
477 <value name="UNPAUSED" />
478 <value name="NOTFOUND" />
479 </variable>
480 </variablelist>
481 <example title="Unpause queue member">
482 same => n,UnpauseQueueMember(,SIP/3000)
483 </example>
484 </description>
485 <see-also>
486 <ref type="application">Queue</ref>
487 <ref type="application">QueueLog</ref>
488 <ref type="application">AddQueueMember</ref>
489 <ref type="application">RemoveQueueMember</ref>
490 <ref type="application">PauseQueueMember</ref>
491 <ref type="application">UnpauseQueueMember</ref>
492 <ref type="function">QUEUE_VARIABLES</ref>
493 <ref type="function">QUEUE_MEMBER</ref>
494 <ref type="function">QUEUE_MEMBER_COUNT</ref>
495 <ref type="function">QUEUE_EXISTS</ref>
496 <ref type="function">QUEUE_GET_CHANNEL</ref>
497 <ref type="function">QUEUE_WAITING_COUNT</ref>
498 <ref type="function">QUEUE_MEMBER_LIST</ref>
499 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
500 </see-also>
501 </application>
502 <application name="QueueLog" language="en_US">
503 <synopsis>
504 Writes to the queue_log file.
505 </synopsis>
506 <syntax>
507 <parameter name="queuename" required="true" />
508 <parameter name="uniqueid" required="true" />
509 <parameter name="agent" required="true" />
510 <parameter name="event" required="true" />
511 <parameter name="additionalinfo" />
512 </syntax>
513 <description>
514 <para>Allows you to write your own events into the queue log.</para>
515 <example title="Log custom queue event">
516 same => n,QueueLog(101,${UNIQUEID},${AGENT},WENTONBREAK,600)
517 </example>
518 </description>
519 <see-also>
520 <ref type="application">Queue</ref>
521 <ref type="application">QueueLog</ref>
522 <ref type="application">AddQueueMember</ref>
523 <ref type="application">RemoveQueueMember</ref>
524 <ref type="application">PauseQueueMember</ref>
525 <ref type="application">UnpauseQueueMember</ref>
526 <ref type="function">QUEUE_VARIABLES</ref>
527 <ref type="function">QUEUE_MEMBER</ref>
528 <ref type="function">QUEUE_MEMBER_COUNT</ref>
529 <ref type="function">QUEUE_EXISTS</ref>
530 <ref type="function">QUEUE_GET_CHANNEL</ref>
531 <ref type="function">QUEUE_WAITING_COUNT</ref>
532 <ref type="function">QUEUE_MEMBER_LIST</ref>
533 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
534 </see-also>
535 </application>
536 <application name="QueueUpdate" language="en_US">
537 <synopsis>
538 Writes to the queue_log file for outbound calls and updates Realtime Data.
539 Is used at h extension to be able to have all the parameters.
540 </synopsis>
541 <syntax>
542 <parameter name="queuename" required="true" />
543 <parameter name="uniqueid" required="true" />
544 <parameter name="agent" required="true" />
545 <parameter name="status" required="true" />
546 <parameter name="talktime" required="true" />
547 <parameter name="params" required="false" />
548 </syntax>
549 <description>
550 <para>Allows you to write Outbound events into the queue log.</para>
551 <example title="Write outbound event into queue log">
552 exten => h,1,QueueUpdate(${QUEUE}, ${UNIQUEID}, ${AGENT}, ${DIALSTATUS}, ${ANSWEREDTIME}, ${DIALEDTIME} | ${DIALEDNUMBER})
553 </example>
554 </description>
555 </application>
556 <function name="QUEUE_VARIABLES" language="en_US">
557 <synopsis>
558 Return Queue information in variables.
559 </synopsis>
560 <syntax>
561 <parameter name="queuename" required="true">
562 <enumlist>
563 <enum name="QUEUEMAX">
564 <para>Maxmimum number of calls allowed.</para>
565 </enum>
566 <enum name="QUEUESTRATEGY">
567 <para>The strategy of the queue.</para>
568 </enum>
569 <enum name="QUEUECALLS">
570 <para>Number of calls currently in the queue.</para>
571 </enum>
572 <enum name="QUEUEHOLDTIME">
573 <para>Current average hold time.</para>
574 </enum>
575 <enum name="QUEUECOMPLETED">
576 <para>Number of completed calls for the queue.</para>
577 </enum>
578 <enum name="QUEUEABANDONED">
579 <para>Number of abandoned calls.</para>
580 </enum>
581 <enum name="QUEUESRVLEVEL">
582 <para>Queue service level.</para>
583 </enum>
584 <enum name="QUEUESRVLEVELPERF">
585 <para>Current service level performance.</para>
586 </enum>
587 </enumlist>
588 </parameter>
589 </syntax>
590 <description>
591 <para>Makes the following queue variables available.</para>
592 <para>Returns <literal>0</literal> if queue is found and setqueuevar is defined, <literal>-1</literal> otherwise.</para>
593 </description>
594 <see-also>
595 <ref type="application">Queue</ref>
596 <ref type="application">QueueLog</ref>
597 <ref type="application">AddQueueMember</ref>
598 <ref type="application">RemoveQueueMember</ref>
599 <ref type="application">PauseQueueMember</ref>
600 <ref type="application">UnpauseQueueMember</ref>
601 <ref type="function">QUEUE_VARIABLES</ref>
602 <ref type="function">QUEUE_MEMBER</ref>
603 <ref type="function">QUEUE_MEMBER_COUNT</ref>
604 <ref type="function">QUEUE_EXISTS</ref>
605 <ref type="function">QUEUE_GET_CHANNEL</ref>
606 <ref type="function">QUEUE_WAITING_COUNT</ref>
607 <ref type="function">QUEUE_MEMBER_LIST</ref>
608 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
609 </see-also>
610 </function>
611 <function name="QUEUE_MEMBER" language="en_US">
612 <synopsis>
613 Provides a count of queue members based on the provided criteria, or updates a
614 queue member's settings.
615 </synopsis>
616 <syntax>
617 <parameter name="queuename" required="false" />
618 <parameter name="option" required="true">
619 <enumlist>
620 <enum name="logged">
621 <para>Returns the number of logged-in members for the specified queue.</para>
622 </enum>
623 <enum name="free">
624 <para>Returns the number of logged-in members for the specified queue that either can take calls or are currently wrapping up after a previous call.</para>
625 </enum>
626 <enum name="ready">
627 <para>Returns the number of logged-in members for the specified queue that are immediately available to answer a call.</para>
628 </enum>
629 <enum name="count">
630 <para>Returns the total number of members for the specified queue.</para>
631 </enum>
632 <enum name="penalty">
633 <para>Gets or sets queue member penalty. If
634 <replaceable>queuename</replaceable> is not specified
635 when setting the penalty then the penalty is set in all queues
636 the interface is a member.</para>
637 </enum>
638 <enum name="paused">
639 <para>Gets or sets queue member paused status. If
640 <replaceable>queuename</replaceable> is not specified
641 when setting the paused status then the paused status is set
642 in all queues the interface is a member.</para>
643 </enum>
644 <enum name="ringinuse">
645 <para>Gets or sets queue member ringinuse. If
646 <replaceable>queuename</replaceable> is not specified
647 when setting ringinuse then ringinuse is set
648 in all queues the interface is a member.</para>
649 </enum>
650 </enumlist>
651 </parameter>
652 <parameter name="interface" required="false" />
653 </syntax>
654 <description>
655 <para>Allows access to queue counts [R] and member information [R/W].</para>
656 <para><replaceable>queuename</replaceable> is required for all read operations.</para>
657 <para><replaceable>interface</replaceable> is required for all member operations.</para>
658 </description>
659 <see-also>
660 <ref type="application">Queue</ref>
661 <ref type="application">QueueLog</ref>
662 <ref type="application">AddQueueMember</ref>
663 <ref type="application">RemoveQueueMember</ref>
664 <ref type="application">PauseQueueMember</ref>
665 <ref type="application">UnpauseQueueMember</ref>
666 <ref type="function">QUEUE_VARIABLES</ref>
667 <ref type="function">QUEUE_MEMBER</ref>
668 <ref type="function">QUEUE_MEMBER_COUNT</ref>
669 <ref type="function">QUEUE_EXISTS</ref>
670 <ref type="function">QUEUE_GET_CHANNEL</ref>
671 <ref type="function">QUEUE_WAITING_COUNT</ref>
672 <ref type="function">QUEUE_MEMBER_LIST</ref>
673 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
674 </see-also>
675 </function>
676 <function name="QUEUE_MEMBER_COUNT" language="en_US">
677 <synopsis>
678 Count number of members answering a queue.
679 </synopsis>
680 <syntax>
681 <parameter name="queuename" required="true" />
682 </syntax>
683 <description>
684 <para>Returns the number of members currently associated with the specified <replaceable>queuename</replaceable>.</para>
685 <warning><para>This function has been deprecated in favor of the <literal>QUEUE_MEMBER()</literal> function</para></warning>
686 </description>
687 <see-also>
688 <ref type="application">Queue</ref>
689 <ref type="application">QueueLog</ref>
690 <ref type="application">AddQueueMember</ref>
691 <ref type="application">RemoveQueueMember</ref>
692 <ref type="application">PauseQueueMember</ref>
693 <ref type="application">UnpauseQueueMember</ref>
694 <ref type="function">QUEUE_VARIABLES</ref>
695 <ref type="function">QUEUE_MEMBER</ref>
696 <ref type="function">QUEUE_MEMBER_COUNT</ref>
697 <ref type="function">QUEUE_EXISTS</ref>
698 <ref type="function">QUEUE_GET_CHANNEL</ref>
699 <ref type="function">QUEUE_WAITING_COUNT</ref>
700 <ref type="function">QUEUE_MEMBER_LIST</ref>
701 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
702 </see-also>
703 </function>
704 <function name="QUEUE_EXISTS" language="en_US">
705 <synopsis>
706 Check if a named queue exists on this server
707 </synopsis>
708 <syntax>
709 <parameter name="queuename" />
710 </syntax>
711 <description>
712 <para>Returns 1 if the specified queue exists, 0 if it does not</para>
713 </description>
714 <see-also>
715 <ref type="application">Queue</ref>
716 <ref type="application">QueueLog</ref>
717 <ref type="application">AddQueueMember</ref>
718 <ref type="application">RemoveQueueMember</ref>
719 <ref type="application">PauseQueueMember</ref>
720 <ref type="application">UnpauseQueueMember</ref>
721 <ref type="function">QUEUE_VARIABLES</ref>
722 <ref type="function">QUEUE_MEMBER</ref>
723 <ref type="function">QUEUE_MEMBER_COUNT</ref>
724 <ref type="function">QUEUE_EXISTS</ref>
725 <ref type="function">QUEUE_GET_CHANNEL</ref>
726 <ref type="function">QUEUE_WAITING_COUNT</ref>
727 <ref type="function">QUEUE_MEMBER_LIST</ref>
728 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
729 </see-also>
730 </function>
731 <function name="QUEUE_GET_CHANNEL" language="en_US">
732 <synopsis>
733 Return caller at the specified position in a queue.
734 </synopsis>
735 <syntax>
736 <parameter name="queuename" required="true" />
737 <parameter name="position" />
738 </syntax>
739 <description>
740 <para>Returns the caller channel at <replaceable>position</replaceable> in the specified <replaceable>queuename</replaceable>.</para>
741 <para>If <replaceable>position</replaceable> is unspecified the first channel is returned.</para>
742 </description>
743 <see-also>
744 <ref type="application">Queue</ref>
745 <ref type="application">QueueLog</ref>
746 <ref type="application">AddQueueMember</ref>
747 <ref type="application">RemoveQueueMember</ref>
748 <ref type="application">PauseQueueMember</ref>
749 <ref type="application">UnpauseQueueMember</ref>
750 <ref type="function">QUEUE_VARIABLES</ref>
751 <ref type="function">QUEUE_MEMBER</ref>
752 <ref type="function">QUEUE_MEMBER_COUNT</ref>
753 <ref type="function">QUEUE_EXISTS</ref>
754 <ref type="function">QUEUE_WAITING_COUNT</ref>
755 <ref type="function">QUEUE_MEMBER_LIST</ref>
756 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
757 </see-also>
758 </function>
759 <function name="QUEUE_WAITING_COUNT" language="en_US">
760 <synopsis>
761 Count number of calls currently waiting in a queue.
762 </synopsis>
763 <syntax>
764 <parameter name="queuename" />
765 </syntax>
766 <description>
767 <para>Returns the number of callers currently waiting in the specified <replaceable>queuename</replaceable>.</para>
768 </description>
769 <see-also>
770 <ref type="application">Queue</ref>
771 <ref type="application">QueueLog</ref>
772 <ref type="application">AddQueueMember</ref>
773 <ref type="application">RemoveQueueMember</ref>
774 <ref type="application">PauseQueueMember</ref>
775 <ref type="application">UnpauseQueueMember</ref>
776 <ref type="function">QUEUE_VARIABLES</ref>
777 <ref type="function">QUEUE_MEMBER</ref>
778 <ref type="function">QUEUE_MEMBER_COUNT</ref>
779 <ref type="function">QUEUE_EXISTS</ref>
780 <ref type="function">QUEUE_GET_CHANNEL</ref>
781 <ref type="function">QUEUE_WAITING_COUNT</ref>
782 <ref type="function">QUEUE_MEMBER_LIST</ref>
783 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
784 </see-also>
785 </function>
786 <function name="QUEUE_MEMBER_LIST" language="en_US">
787 <synopsis>
788 Returns a list of interfaces on a queue.
789 </synopsis>
790 <syntax>
791 <parameter name="queuename" required="true" />
792 </syntax>
793 <description>
794 <para>Returns a comma-separated list of members associated with the specified <replaceable>queuename</replaceable>.</para>
795 </description>
796 <see-also>
797 <ref type="application">Queue</ref>
798 <ref type="application">QueueLog</ref>
799 <ref type="application">AddQueueMember</ref>
800 <ref type="application">RemoveQueueMember</ref>
801 <ref type="application">PauseQueueMember</ref>
802 <ref type="application">UnpauseQueueMember</ref>
803 <ref type="function">QUEUE_VARIABLES</ref>
804 <ref type="function">QUEUE_MEMBER</ref>
805 <ref type="function">QUEUE_MEMBER_COUNT</ref>
806 <ref type="function">QUEUE_EXISTS</ref>
807 <ref type="function">QUEUE_GET_CHANNEL</ref>
808 <ref type="function">QUEUE_WAITING_COUNT</ref>
809 <ref type="function">QUEUE_MEMBER_LIST</ref>
810 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
811 </see-also>
812 </function>
813 <function name="QUEUE_MEMBER_PENALTY" language="en_US">
814 <synopsis>
815 Gets or sets queue members penalty.
816 </synopsis>
817 <syntax>
818 <parameter name="queuename" required="true" />
819 <parameter name="interface" required="true" />
820 </syntax>
821 <description>
822 <para>Gets or sets queue members penalty.</para>
823 <warning><para>This function has been deprecated in favor of the <literal>QUEUE_MEMBER()</literal> function</para></warning>
824 </description>
825 <see-also>
826 <ref type="application">Queue</ref>
827 <ref type="application">QueueLog</ref>
828 <ref type="application">AddQueueMember</ref>
829 <ref type="application">RemoveQueueMember</ref>
830 <ref type="application">PauseQueueMember</ref>
831 <ref type="application">UnpauseQueueMember</ref>
832 <ref type="function">QUEUE_VARIABLES</ref>
833 <ref type="function">QUEUE_MEMBER</ref>
834 <ref type="function">QUEUE_MEMBER_COUNT</ref>
835 <ref type="function">QUEUE_EXISTS</ref>
836 <ref type="function">QUEUE_GET_CHANNEL</ref>
837 <ref type="function">QUEUE_WAITING_COUNT</ref>
838 <ref type="function">QUEUE_MEMBER_LIST</ref>
839 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
840 </see-also>
841 </function>
842 <manager name="QueueStatus" language="en_US">
843 <synopsis>
844 Show queue status.
845 </synopsis>
846 <syntax>
847 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
848 <parameter name="Queue">
849 <para>Limit the response to the status of the specified queue.</para>
850 </parameter>
851 <parameter name="Member">
852 <para>Limit the response to the status of the specified member.</para>
853 </parameter>
854 </syntax>
855 <description>
856 <para>Check the status of one or more queues.</para>
857 </description>
858 </manager>
859 <manager name="QueueSummary" language="en_US">
860 <synopsis>
861 Show queue summary.
862 </synopsis>
863 <syntax>
864 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
865 <parameter name="Queue">
866 <para>Queue for which the summary is requested.</para>
867 </parameter>
868 </syntax>
869 <description>
870 <para>Request the manager to send a QueueSummary event.</para>
871 </description>
872 </manager>
873 <manager name="QueueAdd" language="en_US">
874 <synopsis>
875 Add interface to queue.
876 </synopsis>
877 <syntax>
878 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
879 <parameter name="Queue" required="true">
880 <para>Queue's name.</para>
881 </parameter>
882 <parameter name="Interface" required="true">
883 <para>The name of the interface (tech/name) to add to the queue.</para>
884 </parameter>
885 <parameter name="Penalty">
886 <para>A penalty (number) to apply to this member. Asterisk will distribute calls to members with higher penalties only after attempting to distribute calls to those with lower penalty.</para>
887 </parameter>
888 <parameter name="Paused">
889 <para>To pause or not the member initially (true/false or 1/0).</para>
890 </parameter>
891 <parameter name="Reason" required="false">
892 <para>Text description why the member is paused.</para>
893 </parameter>
894 <parameter name="MemberName">
895 <para>Text alias for the interface.</para>
896 </parameter>
897 <parameter name="StateInterface" />
898 </syntax>
899 <description>
900 </description>
901 </manager>
902 <manager name="QueueRemove" language="en_US">
903 <synopsis>
904 Remove interface from queue.
905 </synopsis>
906 <syntax>
907 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
908 <parameter name="Queue" required="true">
909 <para>The name of the queue to take action on.</para>
910 </parameter>
911 <parameter name="Interface" required="true">
912 <para>The interface (tech/name) to remove from queue.</para>
913 </parameter>
914 </syntax>
915 <description>
916 </description>
917 </manager>
918 <manager name="QueuePause" language="en_US">
919 <synopsis>
920 Makes a queue member temporarily unavailable.
921 </synopsis>
922 <syntax>
923 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
924 <parameter name="Interface" required="true">
925 <para>The name of the interface (tech/name) to pause or unpause.</para>
926 </parameter>
927 <parameter name="Paused" required="true">
928 <para>Pause or unpause the interface. Set to 'true' to pause the member or 'false' to unpause.</para>
929 </parameter>
930 <parameter name="Queue" required="false">
931 <para>The name of the queue in which to pause or unpause this member. If not specified, the member will be paused or unpaused in all the queues it is a member of.</para>
932 </parameter>
933 <parameter name="Reason" required="false">
934 <para>Text description, returned in the event QueueMemberPaused.</para>
935 </parameter>
936 </syntax>
937 <description>
938 <para>Pause or unpause a member in a queue.</para>
939 </description>
940 </manager>
941 <manager name="QueueLog" language="en_US">
942 <synopsis>
943 Adds custom entry in queue_log.
944 </synopsis>
945 <syntax>
946 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
947 <parameter name="Queue" required="true" />
948 <parameter name="Event" required="true" />
949 <parameter name="Uniqueid" />
950 <parameter name="Interface" />
951 <parameter name="Message" />
952 </syntax>
953 <description>
954 </description>
955 </manager>
956 <manager name="QueuePenalty" language="en_US">
957 <synopsis>
958 Set the penalty for a queue member.
959 </synopsis>
960 <syntax>
961 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
962 <parameter name="Interface" required="true">
963 <para>The interface (tech/name) of the member whose penalty to change.</para>
964 </parameter>
965 <parameter name="Penalty" required="true">
966 <para>The new penalty (number) for the member. Must be nonnegative.</para>
967 </parameter>
968 <parameter name="Queue">
969 <para>If specified, only set the penalty for the member of this queue. Otherwise, set the penalty for the member in all queues to which the member belongs.</para>
970 </parameter>
971 </syntax>
972 <description>
973 <para>Change the penalty of a queue member</para>
974 </description>
975 </manager>
976 <manager name="QueueMemberRingInUse" language="en_US">
977 <synopsis>
978 Set the ringinuse value for a queue member.
979 </synopsis>
980 <syntax>
981 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
982 <parameter name="Interface" required="true" />
983 <parameter name="RingInUse" required="true" />
984 <parameter name="Queue" />
985 </syntax>
986 <description>
987 </description>
988 </manager>
989 <manager name="QueueRule" language="en_US">
990 <synopsis>
991 Queue Rules.
992 </synopsis>
993 <syntax>
994 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
995 <parameter name="Rule">
996 <para>The name of the rule in queuerules.conf whose contents to list.</para>
997 </parameter>
998 </syntax>
999 <description>
1000 <para>List queue rules defined in queuerules.conf</para>
1001 </description>
1002 </manager>
1003 <manager name="QueueReload" language="en_US">
1004 <synopsis>
1005 Reload a queue, queues, or any sub-section of a queue or queues.
1006 </synopsis>
1007 <syntax>
1008 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1009 <parameter name="Queue">
1010 <para>The name of the queue to take action on. If no queue name is specified, then all queues are affected.</para>
1011 </parameter>
1012 <parameter name="Members">
1013 <para>Whether to reload the queue's members.</para>
1014 <enumlist>
1015 <enum name="yes" />
1016 <enum name="no" />
1017 </enumlist>
1018 </parameter>
1019 <parameter name="Rules">
1020 <para>Whether to reload queuerules.conf</para>
1021 <enumlist>
1022 <enum name="yes" />
1023 <enum name="no" />
1024 </enumlist>
1025 </parameter>
1026 <parameter name="Parameters">
1027 <para>Whether to reload the other queue options.</para>
1028 <enumlist>
1029 <enum name="yes" />
1030 <enum name="no" />
1031 </enumlist>
1032 </parameter>
1033 </syntax>
1034 <description>
1035 </description>
1036 </manager>
1037 <manager name="QueueReset" language="en_US">
1038 <synopsis>
1039 Reset queue statistics.
1040 </synopsis>
1041 <syntax>
1042 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1043 <parameter name="Queue">
1044 <para>The name of the queue on which to reset statistics.</para>
1045 </parameter>
1046 </syntax>
1047 <description>
1048 <para>Reset the statistics for a queue.</para>
1049 </description>
1050 </manager>
1051 <manager name="QueueChangePriorityCaller" language="en_US">
1052 <synopsis>
1053 Change priority of a caller on queue.
1054 </synopsis>
1055 <syntax>
1056 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1057 <parameter name="Queue" required="true">
1058 <para>The name of the queue to take action on.</para>
1059 </parameter>
1060 <parameter name="Caller" required="true">
1061 <para>The caller (channel) to change priority on queue.</para>
1062 </parameter>
1063
1064 <parameter name="Priority" required="true">
1065 <para>Priority value for change for caller on queue.</para>
1066 </parameter>
1067 <parameter name="Immediate">
1068 <para>When set to yes will cause the priority change to be reflected immediately, causing the channel to change position within the queue.</para>
1069 </parameter>
1070 </syntax>
1071 <description>
1072 </description>
1073 </manager>
1074 <manager name="QueueWithdrawCaller" language="en_US">
1075 <synopsis>
1076 Request to withdraw a caller from the queue back to the dialplan.
1077 </synopsis>
1078 <syntax>
1079 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1080 <parameter name="Queue" required="true">
1081 <para>The name of the queue to take action on.</para>
1082 </parameter>
1083 <parameter name="Caller" required="true">
1084 <para>The caller (channel) to withdraw from the queue.</para>
1085 </parameter>
1086 <parameter name="WithdrawInfo" required="false">
1087 <para>Optional info to store. If the call is successfully withdrawn from the queue, this information will be available in the QUEUE_WITHDRAW_INFO variable.</para>
1088 </parameter>
1089 </syntax>
1090 <description>
1091 </description>
1092 </manager>
1093
1094 <managerEvent language="en_US" name="QueueParams">
1095 <managerEventInstance class="EVENT_FLAG_AGENT">
1096 <synopsis>Raised in response to the QueueStatus action.</synopsis>
1097 <syntax>
1098 <parameter name="Max">
1099 <para>The name of the queue.</para>
1100 </parameter>
1101 <parameter name="Strategy">
1102 <para>The strategy of the queue.</para>
1103 </parameter>
1104 <parameter name="Calls">
1105 <para>The queue member's channel technology or location.</para>
1106 </parameter>
1107 <parameter name="Holdtime">
1108 <para>The queue's hold time.</para>
1109 </parameter>
1110 <parameter name="TalkTime">
1111 <para>The queue's talk time.</para>
1112 </parameter>
1113 <parameter name="Completed">
1114 <para>The queue's completion time.</para>
1115 </parameter>
1116 <parameter name="Abandoned">
1117 <para>The queue's call abandonment metric.</para>
1118 </parameter>
1119 <parameter name="ServiceLevelPerf">
1120 <para>Primary service level performance metric.</para>
1121 </parameter>
1122 <parameter name="ServiceLevelPerf2">
1123 <para>Secondary service level performance metric.</para>
1124 </parameter>
1125 </syntax>
1126 <see-also>
1127 <ref type="managerEvent">QueueMember</ref>
1128 <ref type="managerEvent">QueueEntry</ref>
1129 </see-also>
1130 </managerEventInstance>
1131 </managerEvent>
1132 <managerEvent language="en_US" name="QueueEntry">
1133 <managerEventInstance class="EVENT_FLAG_AGENT">
1134 <synopsis>Raised in response to the QueueStatus action.</synopsis>
1135 <syntax>
1136 <parameter name="Queue">
1137 <para>The name of the queue.</para>
1138 </parameter>
1139 <parameter name="Position">
1140 <para>The caller's position within the queue.</para>
1141 </parameter>
1142 <parameter name="Channel">
1143 <para>The name of the caller's channel.</para>
1144 </parameter>
1145 <parameter name="Uniqueid">
1146 <para>The unique ID of the channel.</para>
1147 </parameter>
1148 <parameter name="CallerIDNum">
1149 <para>The Caller ID number.</para>
1150 </parameter>
1151 <parameter name="CallerIDName">
1152 <para>The Caller ID name.</para>
1153 </parameter>
1154 <parameter name="ConnectedLineNum">
1155 <para>The bridged party's number.</para>
1156 </parameter>
1157 <parameter name="ConnectedLineName">
1158 <para>The bridged party's name.</para>
1159 </parameter>
1160 <parameter name="Wait">
1161 <para>The caller's wait time.</para>
1162 </parameter>
1163 <parameter name="Priority">
1164 <para>The caller's priority within the queue.</para>
1165 </parameter>
1166 </syntax>
1167 <see-also>
1168 <ref type="managerEvent">QueueParams</ref>
1169 <ref type="managerEvent">QueueMember</ref>
1170 </see-also>
1171 </managerEventInstance>
1172 </managerEvent>
1173 <managerEvent language="en_US" name="QueueMemberStatus">
1174 <managerEventInstance class="EVENT_FLAG_AGENT">
1175 <synopsis>Raised when a Queue member's status has changed.</synopsis>
1176 <syntax>
1177 <parameter name="Queue">
1178 <para>The name of the queue.</para>
1179 </parameter>
1180 <parameter name="MemberName">
1181 <para>The name of the queue member.</para>
1182 </parameter>
1183 <parameter name="Interface">
1184 <para>The queue member's channel technology or location.</para>
1185 </parameter>
1186 <parameter name="StateInterface">
1187 <para>Channel technology or location from which to read device state changes.</para>
1188 </parameter>
1189 <parameter name="Membership">
1190 <enumlist>
1191 <enum name="dynamic"/>
1192 <enum name="realtime"/>
1193 <enum name="static"/>
1194 </enumlist>
1195 </parameter>
1196 <parameter name="Penalty">
1197 <para>The penalty associated with the queue member.</para>
1198 </parameter>
1199 <parameter name="CallsTaken">
1200 <para>The number of calls this queue member has serviced.</para>
1201 </parameter>
1202 <parameter name="LastCall">
1203 <para>The time this member last took a call, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
1204 </parameter>
1205 <parameter name="LastPause">
1206 <para>The time when started last paused the queue member.</para>
1207 </parameter>
1208 <parameter name="LoginTime">
1209 <para>The time this member logged in to the queue, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
1210 </parameter>
1211 <parameter name="InCall">
1212 <para>Set to 1 if member is in call. Set to 0 after LastCall time is updated.</para>
1213 <enumlist>
1214 <enum name="0"/>
1215 <enum name="1"/>
1216 </enumlist>
1217 </parameter>
1218 <parameter name="Status">
1219 <para>The numeric device state status of the queue member.</para>
1220 <enumlist>
1221 <enum name="0"><para>AST_DEVICE_UNKNOWN</para></enum>
1222 <enum name="1"><para>AST_DEVICE_NOT_INUSE</para></enum>
1223 <enum name="2"><para>AST_DEVICE_INUSE</para></enum>
1224 <enum name="3"><para>AST_DEVICE_BUSY</para></enum>
1225 <enum name="4"><para>AST_DEVICE_INVALID</para></enum>
1226 <enum name="5"><para>AST_DEVICE_UNAVAILABLE</para></enum>
1227 <enum name="6"><para>AST_DEVICE_RINGING</para></enum>
1228 <enum name="7"><para>AST_DEVICE_RINGINUSE</para></enum>
1229 <enum name="8"><para>AST_DEVICE_ONHOLD</para></enum>
1230 </enumlist>
1231 </parameter>
1232 <parameter name="Paused">
1233 <enumlist>
1234 <enum name="0"/>
1235 <enum name="1"/>
1236 </enumlist>
1237 </parameter>
1238 <parameter name="PausedReason">
1239 <para>If set when paused, the reason the queue member was paused.</para>
1240 </parameter>
1241 <parameter name="Ringinuse">
1242 <enumlist>
1243 <enum name="0"/>
1244 <enum name="1"/>
1245 </enumlist>
1246 </parameter>
1247 <parameter name="Wrapuptime">
1248 <para>The Wrapup Time of the queue member. If this value is set will override the wrapup time of queue.</para>
1249 </parameter>
1250 </syntax>
1251 </managerEventInstance>
1252 </managerEvent>
1253 <managerEvent language="en_US" name="QueueMemberAdded">
1254 <managerEventInstance class="EVENT_FLAG_AGENT">
1255 <synopsis>Raised when a member is added to the queue.</synopsis>
1256 <syntax>
1257 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
1258 </syntax>
1259 <see-also>
1260 <ref type="managerEvent">QueueMemberRemoved</ref>
1261 <ref type="application">AddQueueMember</ref>
1262 </see-also>
1263 </managerEventInstance>
1264 </managerEvent>
1265 <managerEvent language="en_US" name="QueueMemberRemoved">
1266 <managerEventInstance class="EVENT_FLAG_AGENT">
1267 <synopsis>Raised when a member is removed from the queue.</synopsis>
1268 <syntax>
1269 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
1270 </syntax>
1271 <see-also>
1272 <ref type="managerEvent">QueueMemberAdded</ref>
1273 <ref type="application">RemoveQueueMember</ref>
1274 </see-also>
1275 </managerEventInstance>
1276 </managerEvent>
1277 <managerEvent language="en_US" name="QueueMemberPause">
1278 <managerEventInstance class="EVENT_FLAG_AGENT">
1279 <synopsis>Raised when a member is paused/unpaused in the queue.</synopsis>
1280 <syntax>
1281 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
1282 </syntax>
1283 <see-also>
1284 <ref type="application">PauseQueueMember</ref>
1285 <ref type="application">UnpauseQueueMember</ref>
1286 </see-also>
1287 </managerEventInstance>
1288 </managerEvent>
1289 <managerEvent language="en_US" name="QueueMemberPenalty">
1290 <managerEventInstance class="EVENT_FLAG_AGENT">
1291 <synopsis>Raised when a member's penalty is changed.</synopsis>
1292 <syntax>
1293 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
1294 </syntax>
1295 <see-also>
1296 <ref type="function">QUEUE_MEMBER</ref>
1297 </see-also>
1298 </managerEventInstance>
1299 </managerEvent>
1300 <managerEvent language="en_US" name="QueueMemberRinginuse">
1301 <managerEventInstance class="EVENT_FLAG_AGENT">
1302 <synopsis>Raised when a member's ringinuse setting is changed.</synopsis>
1303 <syntax>
1304 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
1305 </syntax>
1306 <see-also>
1307 <ref type="function">QUEUE_MEMBER</ref>
1308 </see-also>
1309 </managerEventInstance>
1310 </managerEvent>
1311 <managerEvent language="en_US" name="QueueCallerJoin">
1312 <managerEventInstance class="EVENT_FLAG_AGENT">
1313 <synopsis>Raised when a caller joins a Queue.</synopsis>
1314 <syntax>
1315 <channel_snapshot/>
1316 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1317 <parameter name="Position">
1318 <para>This channel's current position in the queue.</para>
1319 </parameter>
1320 <parameter name="Count">
1321 <para>The total number of channels in the queue.</para>
1322 </parameter>
1323 </syntax>
1324 <see-also>
1325 <ref type="managerEvent">QueueCallerLeave</ref>
1326 <ref type="application">Queue</ref>
1327 </see-also>
1328 </managerEventInstance>
1329 </managerEvent>
1330 <managerEvent language="en_US" name="QueueCallerLeave">
1331 <managerEventInstance class="EVENT_FLAG_AGENT">
1332 <synopsis>Raised when a caller leaves a Queue.</synopsis>
1333 <syntax>
1334 <channel_snapshot/>
1335 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1336 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerJoin']/managerEventInstance/syntax/parameter[@name='Count'])" />
1337 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerJoin']/managerEventInstance/syntax/parameter[@name='Position'])" />
1338 </syntax>
1339 <see-also>
1340 <ref type="managerEvent">QueueCallerJoin</ref>
1341 </see-also>
1342 </managerEventInstance>
1343 </managerEvent>
1344 <managerEvent language="en_US" name="QueueCallerAbandon">
1345 <managerEventInstance class="EVENT_FLAG_AGENT">
1346 <synopsis>Raised when a caller abandons the queue.</synopsis>
1347 <syntax>
1348 <channel_snapshot/>
1349 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1350 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerJoin']/managerEventInstance/syntax/parameter[@name='Position'])" />
1351 <parameter name="OriginalPosition">
1352 <para>The channel's original position in the queue.</para>
1353 </parameter>
1354 <parameter name="HoldTime">
1355 <para>The time the channel was in the queue, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
1356 </parameter>
1357 </syntax>
1358 </managerEventInstance>
1359 </managerEvent>
1360 <managerEvent language="en_US" name="AgentCalled">
1361 <managerEventInstance class="EVENT_FLAG_AGENT">
1362 <synopsis>Raised when an queue member is notified of a caller in the queue.</synopsis>
1363 <syntax>
1364 <channel_snapshot/>
1365 <channel_snapshot prefix="Dest"/>
1366 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1367 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
1368 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
1369 </syntax>
1370 <see-also>
1371 <ref type="managerEvent">AgentRingNoAnswer</ref>
1372 <ref type="managerEvent">AgentComplete</ref>
1373 <ref type="managerEvent">AgentConnect</ref>
1374 </see-also>
1375 </managerEventInstance>
1376 </managerEvent>
1377 <managerEvent language="en_US" name="AgentRingNoAnswer">
1378 <managerEventInstance class="EVENT_FLAG_AGENT">
1379 <synopsis>Raised when a queue member is notified of a caller in the queue and fails to answer.</synopsis>
1380 <syntax>
1381 <channel_snapshot/>
1382 <channel_snapshot prefix="Dest"/>
1383 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1384 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
1385 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
1386 <parameter name="RingTime">
1387 <para>The time the queue member was rung, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
1388 </parameter>
1389 </syntax>
1390 <see-also>
1391 <ref type="managerEvent">AgentCalled</ref>
1392 </see-also>
1393 </managerEventInstance>
1394 </managerEvent>
1395 <managerEvent language="en_US" name="AgentComplete">
1396 <managerEventInstance class="EVENT_FLAG_AGENT">
1397 <synopsis>Raised when a queue member has finished servicing a caller in the queue.</synopsis>
1398 <syntax>
1399 <channel_snapshot/>
1400 <channel_snapshot prefix="Dest"/>
1401 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1402 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
1403 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
1404 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerAbandon']/managerEventInstance/syntax/parameter[@name='HoldTime'])" />
1405 <parameter name="TalkTime">
1406 <para>The time the queue member talked with the caller in the queue, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
1407 </parameter>
1408 <parameter name="Reason">
1409 <enumlist>
1410 <enum name="caller"/>
1411 <enum name="agent"/>
1412 <enum name="transfer"/>
1413 </enumlist>
1414 </parameter>
1415 </syntax>
1416 <see-also>
1417 <ref type="managerEvent">AgentCalled</ref>
1418 <ref type="managerEvent">AgentConnect</ref>
1419 </see-also>
1420 </managerEventInstance>
1421 </managerEvent>
1422 <managerEvent language="en_US" name="AgentDump">
1423 <managerEventInstance class="EVENT_FLAG_AGENT">
1424 <synopsis>Raised when a queue member hangs up on a caller in the queue.</synopsis>
1425 <syntax>
1426 <channel_snapshot/>
1427 <channel_snapshot prefix="Dest"/>
1428 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1429 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
1430 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
1431 </syntax>
1432 <see-also>
1433 <ref type="managerEvent">AgentCalled</ref>
1434 <ref type="managerEvent">AgentConnect</ref>
1435 </see-also>
1436 </managerEventInstance>
1437 </managerEvent>
1438 <managerEvent language="en_US" name="AgentConnect">
1439 <managerEventInstance class="EVENT_FLAG_AGENT">
1440 <synopsis>Raised when a queue member answers and is bridged to a caller in the queue.</synopsis>
1441 <syntax>
1442 <channel_snapshot/>
1443 <channel_snapshot prefix="Dest"/>
1444 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1445 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
1446 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
1447 <xi:include xpointer="xpointer(/docs/managerEvent[@name='AgentRingNoAnswer']/managerEventInstance/syntax/parameter[@name='RingTime'])" />
1448 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerAbandon']/managerEventInstance/syntax/parameter[@name='HoldTime'])" />
1449 </syntax>
1450 <see-also>
1451 <ref type="managerEvent">AgentCalled</ref>
1452 <ref type="managerEvent">AgentComplete</ref>
1453 <ref type="managerEvent">AgentDump</ref>
1454 </see-also>
1455 </managerEventInstance>
1456 </managerEvent>
1457 ***/
1458
1459enum {
1461 OPT_GO_ON = (1 << 1),
1470 OPT_NO_RETRY = (1 << 10),
1471 OPT_RINGING = (1 << 11),
1482};
1483
1484enum {
1489 /* note: this entry _MUST_ be the last one in the enum */
1492
1517
1518
1520 AQMFLAG_PAUSED = (1 << 1),
1521 AQMFLAG_REASON = (1 << 2),
1522};
1523
1526 AQM_OPT_ARG_ARRAY_SIZE, /* Always last element of the enum */
1527};
1528
1533
1534enum {
1543};
1544
1545enum {
1550
1556};
1557
1558static const struct strategy {
1560 const char *name;
1561} strategies[] = {
1562 { QUEUE_STRATEGY_RINGALL, "ringall" },
1563 { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
1564 { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
1565 { QUEUE_STRATEGY_RANDOM, "random" },
1566 { QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
1567 { QUEUE_STRATEGY_RRMEMORY, "roundrobin" },
1568 { QUEUE_STRATEGY_LINEAR, "linear" },
1569 { QUEUE_STRATEGY_WRANDOM, "wrandom"},
1570 { QUEUE_STRATEGY_RRORDERED, "rrordered"},
1572
1573static const struct autopause {
1575 const char *name;
1576} autopausesmodes [] = {
1577 { QUEUE_AUTOPAUSE_OFF,"no" },
1578 { QUEUE_AUTOPAUSE_ON, "yes" },
1579 { QUEUE_AUTOPAUSE_ALL,"all" },
1581
1582#define DEFAULT_RETRY 5
1583#define DEFAULT_TIMEOUT 15
1584#define RECHECK 1 /*!< Recheck every second to see we we're at the top yet */
1585#define MAX_PERIODIC_ANNOUNCEMENTS 10 /*!< The maximum periodic announcements we can have */
1586/*!
1587 * \brief The minimum number of seconds between position announcements.
1588 * \note The default value of 15 provides backwards compatibility.
1589 */
1590#define DEFAULT_MIN_ANNOUNCE_FREQUENCY 15
1591
1592#define MAX_QUEUE_BUCKETS 53
1593
1594#define RES_OKAY 0 /*!< Action completed */
1595#define RES_EXISTS (-1) /*!< Entry already exists */
1596#define RES_OUTOFMEMORY (-2) /*!< Out of memory */
1597#define RES_NOSUCHQUEUE (-3) /*!< No such queue */
1598#define RES_NOT_DYNAMIC (-4) /*!< Member is not dynamic */
1599#define RES_NOT_CALLER (-5) /*!< Caller not found */
1600
1601static char *app = "Queue";
1602
1603static char *app_aqm = "AddQueueMember" ;
1604
1605static char *app_rqm = "RemoveQueueMember" ;
1606
1607static char *app_pqm = "PauseQueueMember" ;
1608
1609static char *app_upqm = "UnpauseQueueMember" ;
1610
1611static char *app_ql = "QueueLog" ;
1612
1613static char *app_qupd = "QueueUpdate";
1614
1615/*! \brief Persistent Members astdb family */
1616static const char * const pm_family = "Queue/PersistentMembers";
1617
1618/*! \brief queues.conf [general] option */
1620
1621/*! \brief Records that one or more queues use weight */
1622static int use_weight;
1623
1624/*! \brief queues.conf [general] option */
1626
1627/*! \brief queues.conf [general] option */
1629
1630/*! \brief queues.conf [general] option */
1632
1633/*! \brief queuerules.conf [general] option */
1635
1636/*! \brief Subscription to device state change messages */
1638
1639/*! \brief queues.conf [general] option */
1641
1642/*! \brief queues.conf [general] option */
1644
1645/*! \brief queues.conf [general] option */
1647
1648/*! \brief name of the ringinuse field in the realtime database */
1650
1651/*! \brief does realtime backend support reason_paused */
1653
1664};
1665
1666static const struct {
1668 char *text;
1669} queue_results[] = {
1670 { QUEUE_UNKNOWN, "UNKNOWN" },
1671 { QUEUE_TIMEOUT, "TIMEOUT" },
1672 { QUEUE_JOINEMPTY,"JOINEMPTY" },
1673 { QUEUE_LEAVEEMPTY, "LEAVEEMPTY" },
1674 { QUEUE_JOINUNAVAIL, "JOINUNAVAIL" },
1675 { QUEUE_LEAVEUNAVAIL, "LEAVEUNAVAIL" },
1676 { QUEUE_FULL, "FULL" },
1677 { QUEUE_CONTINUE, "CONTINUE" },
1678 { QUEUE_WITHDRAW, "WITHDRAW" },
1680
1684};
1685
1686/*! \brief We define a custom "local user" structure because we
1687 * use it not only for keeping track of what is in use but
1688 * also for keeping track of who we're dialing.
1689 *
1690 * There are two "links" defined in this structure, q_next and call_next.
1691 * q_next links ALL defined callattempt structures into a linked list. call_next is
1692 * a link which allows for a subset of the callattempts to be traversed. This subset
1693 * is used in wait_for_answer so that irrelevant callattempts are not traversed. This
1694 * also is helpful so that queue logs are always accurate in the case where a call to
1695 * a member times out, especially if using the ringall strategy.
1696*/
1697
1702 char interface[256]; /*!< An Asterisk dial string (not a channel name) */
1705 /*! Saved connected party info from an AST_CONTROL_CONNECTED_LINE. */
1707 /*! TRUE if an AST_CONTROL_CONNECTED_LINE update was saved to the connected element. */
1709 /*! TRUE if the connected line update is blocked. */
1711 /*! TRUE if caller id is not available for connected line */
1712 unsigned int dial_callerid_absent:1;
1713 /*! TRUE if the call is still active */
1714 unsigned int stillgoing:1;
1716 /*! Original channel name. Must be freed. Could be NULL if allocation failed. */
1718};
1719
1720
1722 struct call_queue *parent; /*!< What queue is our parent */
1723 char moh[MAX_MUSICCLASS]; /*!< Name of musiconhold to be used */
1724 char announce[PATH_MAX]; /*!< Announcement to play for member when call is answered */
1725 char context[AST_MAX_CONTEXT]; /*!< Context when user exits queue */
1726 char digits[AST_MAX_EXTENSION]; /*!< Digits entered while in queue */
1727 const char *predial_callee; /*!< Gosub app arguments for outgoing calls. NULL if not supplied. */
1728 int valid_digits; /*!< Digits entered correspond to valid extension. Exited */
1729 int pos; /*!< Where we are in the queue */
1730 int prio; /*!< Our priority */
1731 int last_pos_said; /*!< Last position we told the user */
1732 int ring_when_ringing; /*!< Should we only use ring indication when a channel is ringing? */
1733 time_t last_periodic_announce_time; /*!< The last time we played a periodic announcement */
1734 int last_periodic_announce_sound; /*!< The last periodic announcement we made */
1735 time_t last_pos; /*!< Last time we told the user their position */
1736 int opos; /*!< Where we started in the queue */
1737 int handled; /*!< Whether our call was handled */
1738 int pending; /*!< Non-zero if we are attempting to call a member */
1739 int max_penalty; /*!< Limit the members that can take this call to this penalty or lower */
1740 int min_penalty; /*!< Limit the members that can take this call to this penalty or higher */
1741 int raise_penalty; /*!< Float lower penalty members to a minimum penalty */
1742 int linpos; /*!< If using linear strategy, what position are we at? */
1743 int linwrapped; /*!< Is the linpos wrapped? */
1744 time_t start; /*!< When we started holding */
1745 time_t expire; /*!< When this entry should expire (time out of queue) */
1746 int cancel_answered_elsewhere; /*!< Whether we should force the CAE flag on this call (C) option*/
1747 unsigned int withdraw:1; /*!< Should this call exit the queue at its next iteration? Used for QueueWithdrawCaller */
1748 char *withdraw_info; /*!< Optional info passed by the caller of QueueWithdrawCaller */
1749 struct ast_channel *chan; /*!< Our channel */
1750 AST_LIST_HEAD_NOLOCK(,penalty_rule) qe_rules; /*!< Local copy of the queue's penalty rules */
1751 struct penalty_rule *pr; /*!< Pointer to the next penalty rule to implement */
1752 struct queue_ent *next; /*!< The next queue entry */
1753};
1754
1755struct member {
1756 char interface[AST_CHANNEL_NAME]; /*!< Technology/Location to dial to reach this member*/
1757 char state_exten[AST_MAX_EXTENSION]; /*!< Extension to get state from (if using hint) */
1758 char state_context[AST_MAX_CONTEXT]; /*!< Context to use when getting state (if using hint) */
1759 char state_interface[AST_CHANNEL_NAME]; /*!< Technology/Location from which to read devicestate changes */
1760 int state_id; /*!< Extension state callback id (if using hint) */
1761 char membername[80]; /*!< Member name to use in queue logs */
1762 int penalty; /*!< Are we a last resort? */
1763 int calls; /*!< Number of calls serviced by this member */
1764 int dynamic; /*!< Are we dynamically added? */
1765 int realtime; /*!< Is this member realtime? */
1766 int status; /*!< Status of queue member */
1767 int paused; /*!< Are we paused (not accepting calls)? */
1768 char reason_paused[80]; /*!< Reason of paused if member is paused */
1769 int queuepos; /*!< In what order (pertains to certain strategies) should this member be called? */
1770 int callcompletedinsl; /*!< Whether the current call was completed within service level */
1771 int wrapuptime; /*!< Wrapup Time */
1772 time_t starttime; /*!< The time at which the member answered the current caller. */
1773 time_t lastcall; /*!< When last successful call was hungup */
1774 time_t lastpause; /*!< When started the last pause */
1775 time_t logintime; /*!< The time when started the login */
1776 struct call_queue *lastqueue; /*!< Last queue we received a call */
1777 unsigned int dead:1; /*!< Used to detect members deleted in realtime */
1778 unsigned int delme:1; /*!< Flag to delete entry on reload */
1779 char rt_uniqueid[80]; /*!< Unique id of realtime member entry */
1780 unsigned int ringinuse:1; /*!< Flag to ring queue members even if their status is 'inuse' */
1781};
1782
1792};
1793
1797};
1798
1799/* values used in multi-bit flags in call_queue */
1800#define ANNOUNCEHOLDTIME_ALWAYS 1
1801#define ANNOUNCEHOLDTIME_ONCE 2
1802#define QUEUE_EVENT_VARIABLES 3
1803
1805 int time; /*!< Number of seconds that need to pass before applying this rule */
1806 int max_value; /*!< The amount specified in the penalty rule for max penalty */
1807 int min_value; /*!< The amount specified in the penalty rule for min penalty */
1808 int raise_value; /*!< The amount specified in the penalty rule for min penalty */
1809 int max_relative; /*!< Is the max adjustment relative? 1 for relative, 0 for absolute */
1810 int min_relative; /*!< Is the min adjustment relative? 1 for relative, 0 for absolute */
1811 int raise_relative; /*!< Is the min adjustment relative? 1 for relative, 0 for absolute */
1812 AST_LIST_ENTRY(penalty_rule) list; /*!< Next penalty_rule */
1813};
1814
1815#define ANNOUNCEPOSITION_YES 1 /*!< We announce position */
1816#define ANNOUNCEPOSITION_NO 2 /*!< We don't announce position */
1817#define ANNOUNCEPOSITION_MORE_THAN 3 /*!< We say "Currently there are more than <limit>" */
1818#define ANNOUNCEPOSITION_LIMIT 4 /*!< We not announce position more than <limit> */
1819
1822 /*! Queue name */
1824 /*! Music on Hold class */
1826 /*! Announcement to play when call is answered */
1828 /*! Exit context */
1830 /*! Gosub to run upon member connection */
1832 /*! Default rule to use if none specified in call to Queue() */
1834 /*! Sound file: "Your call is now first in line" (def. queue-youarenext) */
1836 /*! Sound file: "There are currently" (def. queue-thereare) */
1838 /*! Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting) */
1840 /*! Sound file: "Currently there are more than" (def. queue-quantity1) */
1842 /*! Sound file: "callers waiting to speak with a representative" (def. queue-quantity2) */
1844 /*! Sound file: "The current estimated total holdtime is" (def. queue-holdtime) */
1846 /*! Sound file: "minutes." (def. queue-minutes) */
1848 /*! Sound file: "minute." (def. queue-minute) */
1850 /*! Sound file: "seconds." (def. queue-seconds) */
1852 /*! Sound file: "Thank you for your patience." (def. queue-thankyou) */
1854 /*! Sound file: Custom announce for caller, no default */
1856 /*! Sound file: "Hold time" (def. queue-reporthold) */
1859 /*! Sound files: Custom announce, no default */
1861 unsigned int dead:1;
1862 unsigned int ringinuse:1;
1863 unsigned int announce_to_first_user:1; /*!< Whether or not we announce to the first user in a queue */
1864 unsigned int setinterfacevar:1;
1865 unsigned int setqueuevar:1;
1866 unsigned int setqueueentryvar:1;
1867 unsigned int reportholdtime:1;
1868 unsigned int wrapped:1;
1869 unsigned int timeoutrestart:1;
1870 unsigned int announceholdtime:2;
1871 unsigned int announceposition:3;
1872 unsigned int announceposition_only_up:1; /*!< Only announce position if it has improved */
1874 unsigned int realtime:1;
1875 unsigned int found:1;
1877 unsigned int autopausebusy:1;
1878 unsigned int autopauseunavail:1;
1881 int announcepositionlimit; /*!< How many positions we announce? */
1882 int announcefrequency; /*!< How often to announce their position */
1883 int minannouncefrequency; /*!< The minimum number of seconds between position announcements (def. 15) */
1884 int periodicannouncestartdelay; /*!< How long into the queue should the periodic accouncement start */
1885 int periodicannouncefrequency; /*!< How often to play periodic announcement */
1886 int numperiodicannounce; /*!< The number of periodic announcements configured */
1887 int randomperiodicannounce; /*!< Are periodic announcments randomly chosen */
1888 int roundingseconds; /*!< How many seconds do we round to? */
1889 int holdtime; /*!< Current avg holdtime, based on an exponential average */
1890 int talktime; /*!< Current avg talktime, based on the same exponential average */
1891 int callscompleted; /*!< Number of queue calls completed */
1892 int callsabandoned; /*!< Number of queue calls abandoned */
1893 int callsabandonedinsl; /*!< Number of queue calls abandoned in servicelevel */
1894 int servicelevel; /*!< seconds setting for servicelevel*/
1895 int callscompletedinsl; /*!< Number of calls answered with servicelevel*/
1896 char monfmt[8]; /*!< Format to use when recording calls */
1897 int count; /*!< How many entries */
1898 int maxlen; /*!< Max number of entries */
1899 int wrapuptime; /*!< Wrapup Time */
1900 int penaltymemberslimit; /*!< Disregard penalty when queue has fewer than this many members */
1901
1902 int retry; /*!< Retry calling everyone after this amount of time */
1903 int timeout; /*!< How long to wait for an answer */
1904 int weight; /*!< Respective weight */
1905 int autopause; /*!< Auto pause queue members if they fail to answer */
1906 int autopausedelay; /*!< Delay auto pause for autopausedelay seconds since last call */
1907 int timeoutpriority; /*!< Do we allow a fraction of the timeout to occur for a ring? */
1908
1909 /* Queue strategy things */
1910 int rrpos; /*!< Round Robin - position */
1911 int memberdelay; /*!< Seconds to delay connecting member to caller */
1912 int autofill; /*!< Ignore the head call status and ring an available agent */
1913
1914 int log_restricted_caller_id:1; /*!< Whether log Restricted Caller ID */
1915
1916 struct ao2_container *members; /*!< Head of the list of members */
1917 struct queue_ent *head; /*!< Head of the list of callers */
1918 AST_LIST_ENTRY(call_queue) list; /*!< Next call queue */
1919 AST_LIST_HEAD_NOLOCK(, penalty_rule) rules; /*!< The list of penalty rules to invoke */
1920};
1921
1923 char name[80];
1926};
1927
1929
1930static struct ao2_container *queues;
1931
1932static void update_realtime_members(struct call_queue *q);
1933static struct member *interface_exists(struct call_queue *q, const char *interface);
1934static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
1935static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime);
1936
1937static struct member *find_member_by_queuename_and_interface(const char *queuename, const char *interface);
1938/*! \brief sets the QUEUESTATUS channel variable */
1939static void set_queue_result(struct ast_channel *chan, enum queue_result res)
1940{
1941 int i;
1942
1943 for (i = 0; i < ARRAY_LEN(queue_results); i++) {
1944 if (queue_results[i].id == res) {
1945 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
1946 return;
1947 }
1948 }
1949}
1950
1951static const char *int2strat(int strategy)
1952{
1953 int x;
1954
1955 for (x = 0; x < ARRAY_LEN(strategies); x++) {
1956 if (strategy == strategies[x].strategy) {
1957 return strategies[x].name;
1958 }
1959 }
1960
1961 return "<unknown>";
1962}
1963
1964static int strat2int(const char *strategy)
1965{
1966 int x;
1967
1968 for (x = 0; x < ARRAY_LEN(strategies); x++) {
1969 if (!strcasecmp(strategy, strategies[x].name)) {
1970 return strategies[x].strategy;
1971 }
1972 }
1973
1974 return -1;
1975}
1976
1977static int autopause2int(const char *autopause)
1978{
1979 int x;
1980 /*This 'double check' that default value is OFF */
1982 return QUEUE_AUTOPAUSE_OFF;
1983 }
1984
1985 /*This 'double check' is to ensure old values works */
1986 if(ast_true(autopause)) {
1987 return QUEUE_AUTOPAUSE_ON;
1988 }
1989
1990 for (x = 0; x < ARRAY_LEN(autopausesmodes); x++) {
1991 if (!strcasecmp(autopause, autopausesmodes[x].name)) {
1992 return autopausesmodes[x].autopause;
1993 }
1994 }
1995
1996 /*This 'double check' that default value is OFF */
1997 return QUEUE_AUTOPAUSE_OFF;
1998}
1999
2000static int queue_hash_cb(const void *obj, const int flags)
2001{
2002 const struct call_queue *q = obj;
2003
2004 return ast_str_case_hash(q->name);
2005}
2006
2007static int queue_cmp_cb(void *obj, void *arg, int flags)
2008{
2009 struct call_queue *q = obj, *q2 = arg;
2010 return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0;
2011}
2012
2013/*!
2014 * \brief Return wrapuptime
2015 *
2016 * This function checks if wrapuptime in member is set and return this value.
2017 * Otherwise return value the wrapuptime in the queue configuration
2018 * \return integer value
2019 */
2020static int get_wrapuptime(struct call_queue *q, struct member *member)
2021{
2022 if (member->wrapuptime) {
2023 return member->wrapuptime;
2024 }
2025 return q->wrapuptime;
2026}
2027
2028/*! \internal
2029 * \brief ao2_callback, Decreases queuepos of all followers with a queuepos greater than arg.
2030 * \param obj the member being acted on
2031 * \param arg pointer to an integer containing the position value that was removed and requires reduction for anything above
2032 * \param flag unused
2033 */
2034static int queue_member_decrement_followers(void *obj, void *arg, int flag)
2035{
2036 struct member *mem = obj;
2037 int *decrement_followers_after = arg;
2038
2039 if (mem->queuepos > *decrement_followers_after) {
2040 mem->queuepos--;
2041 }
2042
2043 return 0;
2044}
2045
2046/*! \internal
2047 * \brief ao2_callback, finds members in a queue marked for deletion and in a cascading fashion runs queue_member_decrement_followers
2048 * on them. This callback should always be ran before performing mass unlinking of delmarked members from queues.
2049 * \param obj member being acted on
2050 * \param arg pointer to the queue members are being removed from
2051 * \param flag unused
2052 */
2053static int queue_delme_members_decrement_followers(void *obj, void *arg, int flag)
2054{
2055 struct member *mem = obj;
2056 struct call_queue *queue = arg;
2057 int rrpos = mem->queuepos;
2058
2059 if (mem->delme) {
2061 }
2062
2063 return 0;
2064}
2065
2066/*! \internal
2067 * \brief Use this to decrement followers during removal of a member
2068 * \param queue which queue the member is being removed from
2069 * \param mem which member is being removed from the queue
2070 */
2071static void queue_member_follower_removal(struct call_queue *queue, struct member *mem)
2072{
2073 int pos = mem->queuepos;
2074
2075 /* If the position being removed is less than the current place in the queue, reduce the queue position by one so that we don't skip the member
2076 * who would have been next otherwise. */
2077 if (pos < queue->rrpos) {
2078 queue->rrpos--;
2079 }
2080
2082}
2083
2084#define queue_ref(q) ao2_bump(q)
2085#define queue_unref(q) ({ ao2_cleanup(q); NULL; })
2086#define queue_t_ref(q, tag) ao2_t_bump(q, tag)
2087#define queue_t_unref(q, tag) ({ ao2_t_cleanup(q, tag); NULL; })
2088#define queues_t_link(c, q, tag) ao2_t_link(c, q, tag)
2089#define queues_t_unlink(c, q, tag) ao2_t_unlink(c, q, tag)
2090
2091/*! \brief Set variables of queue */
2092static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
2093{
2094 char interfacevar[256]="";
2095 float sl = 0;
2096
2097 ao2_lock(q);
2098
2099 if (q->setqueuevar) {
2100 sl = 0;
2101 if (q->callscompleted > 0) {
2102 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
2103 }
2104
2105 snprintf(interfacevar, sizeof(interfacevar),
2106 "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
2108
2109 ao2_unlock(q);
2110
2111 pbx_builtin_setvar_multiple(chan, interfacevar);
2112 } else {
2113 ao2_unlock(q);
2114 }
2115}
2116
2117/*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
2118static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
2119{
2120 struct queue_ent *cur;
2121
2122 if (!q || !new)
2123 return;
2124 if (prev) {
2125 cur = prev->next;
2126 prev->next = new;
2127 } else {
2128 cur = q->head;
2129 q->head = new;
2130 }
2131 new->next = cur;
2132
2133 /* every queue_ent must have a reference to it's parent call_queue, this
2134 * reference does not go away until the end of the queue_ent's life, meaning
2135 * that even when the queue_ent leaves the call_queue this ref must remain. */
2136 if (!new->parent) {
2137 queue_ref(q);
2138 new->parent = q;
2139 }
2140 new->pos = ++(*pos);
2141 new->opos = *pos;
2142}
2143
2145{
2147 RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
2148 RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
2149
2150 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
2151 event_string = ast_manager_str_from_json_object(obj->blob, NULL);
2152 if (!channel_string || !event_string) {
2153 return NULL;
2154 }
2155
2157 "%s"
2158 "%s",
2159 ast_str_buffer(channel_string),
2160 ast_str_buffer(event_string));
2161}
2162
2164{
2165 return queue_channel_to_ami("QueueCallerJoin", message);
2166}
2167
2169{
2170 return queue_channel_to_ami("QueueCallerLeave", message);
2171}
2172
2174{
2175 return queue_channel_to_ami("QueueCallerAbandon", message);
2176}
2177
2178STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_caller_join_type,
2180 );
2181STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_caller_leave_type,
2183 );
2184STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_caller_abandon_type,
2186 );
2187
2189{
2190 struct ast_json_payload *payload = stasis_message_data(message);
2191 RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
2192
2193 event_string = ast_manager_str_from_json_object(payload->json, NULL);
2194 if (!event_string) {
2195 return NULL;
2196 }
2197
2199 "%s",
2200 ast_str_buffer(event_string));
2201}
2202
2204{
2205 return queue_member_to_ami("QueueMemberStatus", message);
2206}
2207
2209{
2210 return queue_member_to_ami("QueueMemberAdded", message);
2211}
2212
2214{
2215 return queue_member_to_ami("QueueMemberRemoved", message);
2216}
2217
2219{
2220 return queue_member_to_ami("QueueMemberPause", message);
2221}
2222
2224{
2225 return queue_member_to_ami("QueueMemberPenalty", message);
2226}
2227
2229{
2230 return queue_member_to_ami("QueueMemberRinginuse", message);
2231}
2232
2233STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_status_type,
2235 );
2236STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_added_type,
2238 );
2239STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_removed_type,
2241 );
2242STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_pause_type,
2244 );
2245STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_penalty_type,
2247 );
2248STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_ringinuse_type,
2250 );
2251
2253{
2256 struct ast_channel_snapshot *agent;
2257 RAII_VAR(struct ast_str *, caller_event_string, NULL, ast_free);
2258 RAII_VAR(struct ast_str *, agent_event_string, NULL, ast_free);
2259 RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
2260
2262 if (caller) {
2263 caller_event_string = ast_manager_build_channel_state_string(caller);
2264 if (!caller_event_string) {
2265 ast_log(LOG_NOTICE, "No caller event string, bailing\n");
2266 return NULL;
2267 }
2268 }
2269
2270 agent = ast_multi_channel_blob_get_channel(obj, "agent");
2271 if (agent) {
2272 agent_event_string = ast_manager_build_channel_state_string_prefix(agent, "Dest");
2273 if (!agent_event_string) {
2274 ast_log(LOG_NOTICE, "No agent event string, bailing\n");
2275 return NULL;
2276 }
2277 }
2278
2280 if (!event_string) {
2281 return NULL;
2282 }
2283
2285 "%s"
2286 "%s"
2287 "%s",
2288 caller_event_string ? ast_str_buffer(caller_event_string) : "",
2289 agent_event_string ? ast_str_buffer(agent_event_string) : "",
2290 ast_str_buffer(event_string));
2291}
2292
2294{
2295 return queue_multi_channel_to_ami("AgentCalled", message);
2296}
2297
2299{
2300 return queue_multi_channel_to_ami("AgentConnect", message);
2301}
2302
2304{
2305 return queue_multi_channel_to_ami("AgentComplete", message);
2306}
2307
2309{
2310 return queue_multi_channel_to_ami("AgentDump", message);
2311}
2312
2314{
2315 return queue_multi_channel_to_ami("AgentRingNoAnswer", message);
2316}
2317
2318STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_called_type,
2320 );
2321STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_connect_type,
2323 );
2324STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_complete_type,
2326 );
2329 );
2330STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_ringnoanswer_type,
2332 );
2333
2335 struct ast_channel_snapshot *caller_snapshot,
2336 struct ast_channel_snapshot *agent_snapshot,
2337 struct stasis_message_type *type, struct ast_json *blob)
2338{
2339 RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
2340 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
2341
2342 if (!type) {
2343 return;
2344 }
2345
2346 payload = ast_multi_channel_blob_create(blob);
2347 if (!payload) {
2348 return;
2349 }
2350
2351 if (caller_snapshot) {
2352 ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot);
2353 } else {
2354 ast_debug(1, "Empty caller_snapshot; sending incomplete event\n");
2355 }
2356
2357 if (agent_snapshot) {
2358 ast_multi_channel_blob_add_channel(payload, "agent", agent_snapshot);
2359 }
2360
2361 msg = stasis_message_create(type, payload);
2362 if (!msg) {
2363 return;
2364 }
2365
2366 stasis_publish(topic, msg);
2367}
2368
2369static void queue_publish_multi_channel_blob(struct ast_channel *caller, struct ast_channel *agent,
2370 struct stasis_message_type *type, struct ast_json *blob)
2371{
2372 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
2373 RAII_VAR(struct ast_channel_snapshot *, agent_snapshot, NULL, ao2_cleanup);
2374
2375 ast_channel_lock(caller);
2376 caller_snapshot = ast_channel_snapshot_create(caller);
2377 ast_channel_unlock(caller);
2378 ast_channel_lock(agent);
2379 agent_snapshot = ast_channel_snapshot_create(agent);
2380 ast_channel_unlock(agent);
2381
2382 if (!caller_snapshot || !agent_snapshot) {
2383 return;
2384 }
2385
2387 agent_snapshot, type, blob);
2388}
2389
2390/*!
2391 * \internal
2392 * \brief Publish the member blob.
2393 * \since 12.0.0
2394 *
2395 * \param type Stasis message type to publish.
2396 * \param blob The information being published.
2397 *
2398 * \note The json blob reference is passed to this function.
2399 */
2401{
2402 RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
2403 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
2404
2405 if (!blob || !type) {
2406 ast_json_unref(blob);
2407 return;
2408 }
2409
2410 payload = ast_json_payload_create(blob);
2411 ast_json_unref(blob);
2412 if (!payload) {
2413 return;
2414 }
2415
2416 msg = stasis_message_create(type, payload);
2417 if (!msg) {
2418 return;
2419 }
2420
2422}
2423
2424static struct ast_json *queue_member_blob_create(struct call_queue *q, struct member *mem)
2425{
2426 return ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: i, s: i, s: i, s: i, s: i, s: i, s: i, s: i, s: s, s: i, s: i}",
2427 "Queue", q->name,
2428 "MemberName", mem->membername,
2429 "Interface", mem->interface,
2430 "StateInterface", mem->state_interface,
2431 "Membership", (mem->dynamic ? "dynamic" : (mem->realtime ? "realtime" : "static")),
2432 "Penalty", mem->penalty,
2433 "CallsTaken", mem->calls,
2434 "LastCall", (int)mem->lastcall,
2435 "LastPause", (int)mem->lastpause,
2436 "LoginTime", (int)mem->logintime,
2437 "InCall", mem->starttime ? 1 : 0,
2438 "Status", mem->status,
2439 "Paused", mem->paused,
2440 "PausedReason", mem->reason_paused,
2441 "Ringinuse", mem->ringinuse,
2442 "Wrapuptime", mem->wrapuptime);
2443}
2444
2445/*! \brief Check if members are available
2446 *
2447 * This function checks to see if members are available to be called. If any member
2448 * is available, the function immediately returns 0. If no members are available,
2449 * then -1 is returned.
2450 */
2451static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, int raise_penalty, enum empty_conditions conditions, int devstate)
2452{
2453 struct member *member;
2454 struct ao2_iterator mem_iter;
2455
2456 ao2_lock(q);
2457 mem_iter = ao2_iterator_init(q->members, 0);
2458 for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
2459 int penalty = member->penalty;
2460 if (raise_penalty != INT_MAX && penalty < raise_penalty) {
2461 ast_debug(4, "%s is having his penalty raised up from %d to %d\n", member->membername, penalty, raise_penalty);
2462 penalty = raise_penalty;
2463 }
2464 if ((max_penalty != INT_MAX && penalty > max_penalty) || (min_penalty != INT_MAX && penalty < min_penalty)) {
2465 if (conditions & QUEUE_EMPTY_PENALTY) {
2466 ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
2467 continue;
2468 }
2469 }
2470
2471 switch (devstate ? ast_device_state(member->state_interface) : member->status) {
2472 case AST_DEVICE_INVALID:
2473 if (conditions & QUEUE_EMPTY_INVALID) {
2474 ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername);
2475 break;
2476 }
2477 goto default_case;
2479 if (conditions & QUEUE_EMPTY_UNAVAILABLE) {
2480 ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername);
2481 break;
2482 }
2483 goto default_case;
2484 case AST_DEVICE_INUSE:
2485 if (conditions & QUEUE_EMPTY_INUSE) {
2486 ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername);
2487 break;
2488 }
2489 goto default_case;
2490 case AST_DEVICE_RINGING:
2491 if (conditions & QUEUE_EMPTY_RINGING) {
2492 ast_debug(4, "%s is unavailable because his device state is 'ringing'\n", member->membername);
2493 break;
2494 }
2495 goto default_case;
2496 case AST_DEVICE_UNKNOWN:
2497 if (conditions & QUEUE_EMPTY_UNKNOWN) {
2498 ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername);
2499 break;
2500 }
2501 /* Fall-through */
2502 default:
2503 default_case:
2504 if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) {
2505 ast_debug(4, "%s is unavailable because he is paused'\n", member->membername);
2506 break;
2507 } else if ((conditions & QUEUE_EMPTY_WRAPUP)
2508 && member->lastcall
2509 && get_wrapuptime(q, member)
2510 && (time(NULL) - get_wrapuptime(q, member) < member->lastcall)) {
2511 ast_debug(4, "%s is unavailable because it has only been %d seconds since his last call (wrapup time is %d)\n",
2512 member->membername, (int) (time(NULL) - member->lastcall), get_wrapuptime(q, member));
2513 break;
2514 } else {
2515 ao2_ref(member, -1);
2516 ao2_iterator_destroy(&mem_iter);
2517 ao2_unlock(q);
2518 ast_debug(4, "%s is available.\n", member->membername);
2519 return 0;
2520 }
2521 break;
2522 }
2523 }
2524 ao2_iterator_destroy(&mem_iter);
2525 ao2_unlock(q);
2526
2527 if (!devstate && (conditions & QUEUE_EMPTY_RINGING)) {
2528 /* member state still may be RINGING due to lag in event message - check again with device state */
2529 return get_member_status(q, max_penalty, min_penalty, raise_penalty, conditions, 1);
2530 }
2531 return -1;
2532}
2533
2534/*
2535 * A "pool" of member objects that calls are currently pending on. If an
2536 * agent is a member of multiple queues it's possible for that agent to be
2537 * called by each of the queues at the same time. This happens because device
2538 * state is slow to notify the queue app of one of it's member's being rung.
2539 * This "pool" allows us to track which members are currently being rung while
2540 * we wait on the device state change.
2541 */
2543#define MAX_CALL_ATTEMPT_BUCKETS 353
2544
2545static int pending_members_hash(const void *obj, const int flags)
2546{
2547 const struct member *object;
2548 const char *key;
2549
2550 switch (flags & OBJ_SEARCH_MASK) {
2551 case OBJ_SEARCH_KEY:
2552 key = obj;
2553 break;
2554 case OBJ_SEARCH_OBJECT:
2555 object = obj;
2556 key = object->interface;
2557 break;
2558 default:
2559 ast_assert(0);
2560 return 0;
2561 }
2562 return ast_str_case_hash(key);
2563}
2564
2565static int pending_members_cmp(void *obj, void *arg, int flags)
2566{
2567 const struct member *object_left = obj;
2568 const struct member *object_right = arg;
2569 const char *right_key = arg;
2570 int cmp;
2571
2572 switch (flags & OBJ_SEARCH_MASK) {
2573 case OBJ_SEARCH_OBJECT:
2574 right_key = object_right->interface;
2575 /* Fall through */
2576 case OBJ_SEARCH_KEY:
2577 cmp = strcasecmp(object_left->interface, right_key);
2578 break;
2580 /* Not supported by container. */
2581 ast_assert(0);
2582 return 0;
2583 default:
2584 cmp = 0;
2585 break;
2586 }
2587 if (cmp) {
2588 return 0;
2589 }
2590 return CMP_MATCH;
2591}
2592
2593static void pending_members_remove(struct member *mem)
2594{
2595 ast_debug(3, "Removed %s from pending_members\n", mem->membername);
2597}
2598
2599/*! \brief set a member's status based on device state of that member's state_interface.
2600 *
2601 * Lock interface list find sc, iterate through each queues queue_member list for member to
2602 * update state inside queues
2603*/
2604static void update_status(struct call_queue *q, struct member *m, const int status)
2605{
2606 if (m->status != status) {
2607 /* If this member has transitioned to being available then update their queue
2608 * information. If they are currently in a call then the leg to the agent will be
2609 * considered done and the call finished.
2610 */
2613 }
2614
2615 m->status = status;
2616
2617 /* Remove the member from the pending members pool only when the status changes.
2618 * This is not done unconditionally because we can occasionally see multiple
2619 * device state notifications of not in use after a previous call has ended,
2620 * including after we have initiated a new call. This is more likely to
2621 * happen when there is latency in the connection to the member.
2622 */
2624
2625 queue_publish_member_blob(queue_member_status_type(), queue_member_blob_create(q, m));
2626 }
2627}
2628
2629/*!
2630 * \internal
2631 * \brief Determine if a queue member is available
2632 * \retval 1 if the member is available
2633 * \retval 0 if the member is not available
2634 */
2635static int is_member_available(struct call_queue *q, struct member *mem)
2636{
2637 int available = 0;
2638 int wrapuptime;
2639
2640 switch (mem->status) {
2641 case AST_DEVICE_INVALID:
2643 break;
2644 case AST_DEVICE_INUSE:
2645 case AST_DEVICE_BUSY:
2646 case AST_DEVICE_RINGING:
2648 case AST_DEVICE_ONHOLD:
2649 if (!mem->ringinuse) {
2650 break;
2651 }
2652 /* else fall through */
2654 case AST_DEVICE_UNKNOWN:
2655 if (!mem->paused) {
2656 available = 1;
2657 }
2658 break;
2659 }
2660
2661 /* Let wrapuptimes override device state availability */
2662 wrapuptime = get_wrapuptime(q, mem);
2663 if (mem->lastcall && wrapuptime && (time(NULL) - wrapuptime < mem->lastcall)) {
2664 available = 0;
2665 }
2666 return available;
2667}
2668
2669/*! \brief set a member's status based on device state of that member's interface*/
2670static void device_state_cb(void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
2671{
2672 struct ao2_iterator miter, qiter;
2673 struct ast_device_state_message *dev_state;
2674 struct member *m;
2675 struct call_queue *q;
2676 char interface[80], *slash_pos;
2677 int found = 0; /* Found this member in any queue */
2678 int found_member; /* Found this member in this queue */
2679 int avail = 0; /* Found an available member in this queue */
2680
2682 return;
2683 }
2684
2685 dev_state = stasis_message_data(msg);
2686 if (dev_state->eid) {
2687 /* ignore non-aggregate states */
2688 return;
2689 }
2690
2691 qiter = ao2_iterator_init(queues, 0);
2692 while ((q = ao2_t_iterator_next(&qiter, "Iterate over queues"))) {
2693 ao2_lock(q);
2694
2695 avail = 0;
2696 found_member = 0;
2697 miter = ao2_iterator_init(q->members, 0);
2698 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
2699 if (!found_member) {
2700 ast_copy_string(interface, m->state_interface, sizeof(interface));
2701
2702 if ((slash_pos = strchr(interface, '/'))) {
2703 if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/'))) {
2704 *slash_pos = '\0';
2705 }
2706 }
2707
2708 if (!strcasecmp(interface, dev_state->device)) {
2709 found_member = 1;
2710 update_status(q, m, dev_state->state);
2711 }
2712 }
2713
2714 /* check every member until we find one NOT_INUSE */
2715 if (!avail) {
2716 avail = is_member_available(q, m);
2717 }
2718 if (avail && found_member) {
2719 /* early exit as we've found an available member and the member of interest */
2720 ao2_ref(m, -1);
2721 break;
2722 }
2723 }
2724
2725 if (found_member) {
2726 found = 1;
2727 if (avail) {
2729 } else {
2731 }
2732 }
2733
2734 ao2_iterator_destroy(&miter);
2735
2736 ao2_unlock(q);
2737 queue_t_unref(q, "Done with iterator");
2738 }
2739 ao2_iterator_destroy(&qiter);
2740
2741 if (found) {
2742 ast_debug(1, "Device '%s' changed to state '%u' (%s)\n",
2743 dev_state->device,
2744 dev_state->state,
2745 ast_devstate2str(dev_state->state));
2746 } else {
2747 ast_debug(3, "Device '%s' changed to state '%u' (%s) but we don't care because they're not a member of any queue.\n",
2748 dev_state->device,
2749 dev_state->state,
2750 ast_devstate2str(dev_state->state));
2751 }
2752
2753 return;
2754}
2755
2756/*! \brief Helper function which converts from extension state to device state values */
2758{
2759 switch (state) {
2762 break;
2765 break;
2766 case AST_EXTENSION_BUSY:
2768 break;
2771 break;
2774 break;
2777 break;
2780 break;
2783 break;
2786 default:
2788 break;
2789 }
2790
2791 return state;
2792}
2793
2794/*!
2795 * \brief Returns if one context includes another context
2796 *
2797 * \param parent Parent context to search for child
2798 * \param child Context to check for inclusion in parent
2799 *
2800 * This function recursively checks if the context child is included in the context parent.
2801 *
2802 * \retval 1 if child is included in parent
2803 * \retval 0 if not
2804 */
2805static int context_included(const char *parent, const char *child);
2806static int context_included(const char *parent, const char *child)
2807{
2808 struct ast_context *c = NULL;
2809
2810 c = ast_context_find(parent);
2811 if (!c) {
2812 /* well, if parent doesn't exist, how can the child be included in it? */
2813 return 0;
2814 }
2815 if (!strcmp(ast_get_context_name(c), parent)) {
2816 /* found the context of the hint app_queue is using. Now, see
2817 if that context includes the one that just changed state */
2818 struct ast_include *inc = NULL;
2819
2820 while ((inc = (struct ast_include*) ast_walk_context_includes(c, inc))) {
2821 const char *includename = ast_get_include_name(inc);
2822 if (!strcasecmp(child, includename)) {
2823 return 1;
2824 }
2825 /* recurse on this context, for nested includes. The
2826 PBX extension parser will prevent infinite recursion. */
2827 if (context_included(includename, child)) {
2828 return 1;
2829 }
2830 }
2831 }
2832 return 0;
2833}
2834
2835static int extension_state_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
2836{
2837 struct ao2_iterator miter, qiter;
2838 struct member *m;
2839 struct call_queue *q;
2840 int state = info->exten_state;
2841 int found = 0, device_state = extensionstate2devicestate(state);
2842
2843 /* only interested in extension state updates involving device states */
2844 if (info->reason != AST_HINT_UPDATE_DEVICE) {
2845 return 0;
2846 }
2847
2848 qiter = ao2_iterator_init(queues, 0);
2849 while ((q = ao2_t_iterator_next(&qiter, "Iterate through queues"))) {
2850 ao2_lock(q);
2851
2852 miter = ao2_iterator_init(q->members, 0);
2853 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
2854 if (!strcmp(m->state_exten, exten) &&
2856 /* context could be included in m->state_context. We need to check. */
2857 found = 1;
2858 update_status(q, m, device_state);
2859 }
2860 }
2861 ao2_iterator_destroy(&miter);
2862
2863 ao2_unlock(q);
2864 queue_t_unref(q, "Done with iterator");
2865 }
2866 ao2_iterator_destroy(&qiter);
2867
2868 if (found) {
2869 ast_debug(1, "Extension '%s@%s' changed to state '%d' (%s)\n", exten, context, device_state, ast_devstate2str(device_state));
2870 } else {
2871 ast_debug(3, "Extension '%s@%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n",
2872 exten, context, device_state, ast_devstate2str(device_state));
2873 }
2874
2875 return 0;
2876}
2877
2878/*! \brief Return the current state of a member */
2879static int get_queue_member_status(struct member *cur)
2880{
2882}
2883
2884static void destroy_queue_member_cb(void *obj)
2885{
2886 struct member *mem = obj;
2887
2888 if (mem->state_id != -1) {
2890 }
2891}
2892
2893/*! \brief allocate space for new queue member and set fields based on parameters passed */
2894static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface, int ringinuse, int wrapuptime)
2895{
2896 struct member *cur;
2897
2898 if ((cur = ao2_alloc(sizeof(*cur), destroy_queue_member_cb))) {
2899 cur->ringinuse = ringinuse;
2900 cur->penalty = penalty;
2901 cur->paused = paused;
2902 cur->wrapuptime = wrapuptime;
2903 if (paused) {
2904 time(&cur->lastpause); /* Update time of last pause */
2905 }
2906 time(&cur->logintime);
2907 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
2910 } else {
2912 }
2914 ast_copy_string(cur->membername, membername, sizeof(cur->membername));
2915 } else {
2916 ast_copy_string(cur->membername, interface, sizeof(cur->membername));
2917 }
2918 if (!strchr(cur->interface, '/')) {
2919 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
2920 }
2921 if (!strncmp(cur->state_interface, "hint:", 5)) {
2922 char *tmp = ast_strdupa(cur->state_interface), *context = tmp;
2923 char *exten = strsep(&context, "@") + 5;
2924
2925 ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten));
2926 ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context));
2927
2929 } else {
2930 cur->state_id = -1;
2931 }
2932 cur->status = get_queue_member_status(cur);
2933 }
2934
2935 return cur;
2936}
2937
2938
2939static int compress_char(const char c)
2940{
2941 if (c < 32) {
2942 return 0;
2943 } else if (c > 96) {
2944 return c - 64;
2945 }
2946 return c - 32;
2947}
2948
2949static int member_hash_fn(const void *obj, const int flags)
2950{
2951 const struct member *mem = obj;
2952 const char *interface = (flags & OBJ_KEY) ? obj : mem->interface;
2953 const char *chname = strchr(interface, '/');
2954 int ret = 0, i;
2955
2956 if (!chname) {
2957 chname = interface;
2958 }
2959 for (i = 0; i < 5 && chname[i]; i++) {
2960 ret += compress_char(chname[i]) << (i * 6);
2961 }
2962 return ret;
2963}
2964
2965static int member_cmp_fn(void *obj1, void *obj2, int flags)
2966{
2967 struct member *mem1 = obj1;
2968 struct member *mem2 = obj2;
2969 const char *interface = (flags & OBJ_KEY) ? obj2 : mem2->interface;
2970
2971 return strcasecmp(mem1->interface, interface) ? 0 : CMP_MATCH | CMP_STOP;
2972}
2973
2974/*!
2975 * \brief Initialize Queue default values.
2976 * \note the queue's lock must be held before executing this function
2977*/
2978static void init_queue(struct call_queue *q)
2979{
2980 int i;
2981 struct penalty_rule *pr_iter;
2982
2983 q->dead = 0;
2984 q->retry = DEFAULT_RETRY;
2986 q->maxlen = 0;
2987
2988 ast_string_field_set(q, announce, "");
2990 ast_string_field_set(q, membergosub, "");
2991 ast_string_field_set(q, defaultrule, "");
2992
2993 q->announcefrequency = 0;
2995 q->announceholdtime = 1;
2997 q->announcepositionlimit = 10; /* Default 10 positions */
2998 q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */
2999 q->roundingseconds = 0; /* Default - don't announce seconds */
3000 q->servicelevel = 0;
3001 q->ringinuse = 1;
3003 q->setinterfacevar = 0;
3004 q->setqueuevar = 0;
3005 q->setqueueentryvar = 0;
3007 q->monfmt[0] = '\0';
3008 q->reportholdtime = 0;
3009 q->wrapuptime = 0;
3010 q->penaltymemberslimit = 0;
3011 q->joinempty = 0;
3012 q->leavewhenempty = 0;
3013 q->memberdelay = 0;
3014 q->weight = 0;
3015 q->timeoutrestart = 0;
3019 q->numperiodicannounce = 0;
3022 q->autopausebusy = 0;
3023 q->autopauseunavail = 0;
3025 q->autopausedelay = 0;
3027 if (!q->members) {
3029 /* linear strategy depends on order, so we have to place all members in a list */
3031 } else {
3034 }
3035 }
3036 q->found = 1;
3037
3038 ast_string_field_set(q, moh, "");
3039 ast_string_field_set(q, sound_next, "queue-youarenext");
3040 ast_string_field_set(q, sound_thereare, "queue-thereare");
3041 ast_string_field_set(q, sound_calls, "queue-callswaiting");
3042 ast_string_field_set(q, queue_quantity1, "queue-quantity1");
3043 ast_string_field_set(q, queue_quantity2, "queue-quantity2");
3044 ast_string_field_set(q, sound_holdtime, "queue-holdtime");
3045 ast_string_field_set(q, sound_minutes, "queue-minutes");
3046 ast_string_field_set(q, sound_minute, "queue-minute");
3047 ast_string_field_set(q, sound_seconds, "queue-seconds");
3048 ast_string_field_set(q, sound_thanks, "queue-thankyou");
3049 ast_string_field_set(q, sound_callerannounce, "");
3050 ast_string_field_set(q, sound_reporthold, "queue-reporthold");
3051
3052 if (!q->sound_periodicannounce[0]) {
3054 }
3055
3056 if (q->sound_periodicannounce[0]) {
3057 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
3058 }
3059
3060 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
3061 if (q->sound_periodicannounce[i]) {
3062 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
3063 }
3064 }
3065
3066 while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list))) {
3067 ast_free(pr_iter);
3068 }
3069
3070 /* On restart assume no members are available.
3071 * The queue_avail hint is a boolean state to indicate whether a member is available or not.
3072 *
3073 * This seems counter intuitive, but is required to light a BLF
3074 * AST_DEVICE_INUSE indicates no members are available.
3075 * AST_DEVICE_NOT_INUSE indicates a member is available.
3076 */
3078}
3079
3080static void clear_queue(struct call_queue *q)
3081{
3082 q->holdtime = 0;
3083 q->callscompleted = 0;
3084 q->callsabandoned = 0;
3085 q->callscompletedinsl = 0;
3086 q->callsabandonedinsl = 0;
3087 q->talktime = 0;
3088
3089 if (q->members) {
3090 struct member *mem;
3091 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
3092 while ((mem = ao2_iterator_next(&mem_iter))) {
3093 mem->calls = 0;
3094 mem->callcompletedinsl = 0;
3095 mem->lastcall = 0;
3096 mem->starttime = 0;
3097 ao2_ref(mem, -1);
3098 }
3099 ao2_iterator_destroy(&mem_iter);
3100 }
3101}
3102
3103/*!
3104 * \brief Change queue penalty by adding rule.
3105 *
3106 * Check rule for errors with time or formatting, see if rule is relative to rest
3107 * of queue, iterate list of rules to find correct insertion point, insert and return.
3108 * \retval -1 on failure
3109 * \retval 0 on success
3110 * \note Call this with the rule_lists locked
3111*/
3112static int insert_penaltychange(const char *list_name, const char *content, const int linenum)
3113{
3114 char *timestr, *maxstr, *minstr, *raisestr, *contentdup;
3115 struct penalty_rule *rule = NULL, *rule_iter;
3116 struct rule_list *rl_iter;
3117 int penaltychangetime, inserted = 0;
3118
3119 if (!(rule = ast_calloc(1, sizeof(*rule)))) {
3120 return -1;
3121 }
3122
3123 contentdup = ast_strdupa(content);
3124
3125 if (!(maxstr = strchr(contentdup, ','))) {
3126 ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum);
3127 ast_free(rule);
3128 return -1;
3129 }
3130
3131 *maxstr++ = '\0';
3132 if ((minstr = strchr(maxstr,','))) {
3133 *minstr++ = '\0';
3134 if ((raisestr = strchr(minstr,','))) {
3135 *raisestr++ = '\0';
3136 }
3137 } else {
3138 raisestr = NULL;
3139 }
3140
3141 timestr = contentdup;
3142 if ((penaltychangetime = atoi(timestr)) < 0) {
3143 ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum);
3144 ast_free(rule);
3145 return -1;
3146 }
3147
3148 rule->time = penaltychangetime;
3149
3150 /* The last check will evaluate true if either no penalty change is indicated for a given rule
3151 * OR if a min penalty change is indicated but no max penalty change is */
3152 if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') {
3153 rule->max_relative = 1;
3154 }
3155
3156 rule->max_value = atoi(maxstr);
3157
3158 if (!ast_strlen_zero(minstr)) {
3159 if (*minstr == '+' || *minstr == '-') {
3160 rule->min_relative = 1;
3161 }
3162 rule->min_value = atoi(minstr);
3163 } else { /*there was no minimum specified, so assume this means no change*/
3164 rule->min_relative = 1;
3165 }
3166
3167 if (!ast_strlen_zero(raisestr)) {
3168 if (*raisestr == '+' || *raisestr == '-') {
3169 rule->raise_relative = 1;
3170 }
3171 rule->raise_value = atoi(raisestr);
3172 } else { /*there was no raise specified, so assume this means no change*/
3173 rule->raise_relative = 1;
3174 }
3175
3176 /*We have the rule made, now we need to insert it where it belongs*/
3177 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){
3178 if (strcasecmp(rl_iter->name, list_name)) {
3179 continue;
3180 }
3181
3182 AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) {
3183 if (rule->time < rule_iter->time) {
3185 inserted = 1;
3186 break;
3187 }
3188 }
3190
3191 if (!inserted) {
3192 AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list);
3193 inserted = 1;
3194 }
3195
3196 break;
3197 }
3198
3199 if (!inserted) {
3200 ast_log(LOG_WARNING, "Unknown rule list name %s; ignoring.\n", list_name);
3201 ast_free(rule);
3202 return -1;
3203 }
3204 return 0;
3205}
3206
3207/*!
3208 * \brief Load queue rules from realtime.
3209 *
3210 * Check rule for errors with time or formatting, see if rule is relative to rest
3211 * of queue, iterate list of rules to find correct insertion point, insert and return.
3212 * \retval -1 on failure
3213 * \retval 0 on success
3214 * \note Call this with the rule_lists locked
3215*/
3216static int load_realtime_rules(void)
3217{
3218 struct ast_config *cfg;
3219 struct rule_list *rl_iter, *new_rl;
3220 struct penalty_rule *pr_iter;
3221 char *rulecat = NULL;
3222
3223 if (!ast_check_realtime("queue_rules")) {
3224 ast_log(LOG_WARNING, "Missing \"queue_rules\" in extconfig.conf\n");
3225 return 0;
3226 }
3227 if (!(cfg = ast_load_realtime_multientry("queue_rules", "rule_name LIKE", "%", SENTINEL))) {
3228 ast_log(LOG_WARNING, "Failed to load queue rules from realtime\n");
3229 return 0;
3230 }
3231 while ((rulecat = ast_category_browse(cfg, rulecat))) {
3232 const char *timestr, *maxstr, *minstr, *raisestr, *rule_name;
3233 int penaltychangetime, rule_exists = 0, inserted = 0;
3234 int max_penalty = 0, min_penalty = 0, raise_penalty = 0;
3235 int min_relative = 0, max_relative = 0, raise_relative = 0;
3236 struct penalty_rule *new_penalty_rule = NULL;
3237
3238 rule_name = ast_variable_retrieve(cfg, rulecat, "rule_name");
3239 if (ast_strlen_zero(rule_name)) {
3240 continue;
3241 }
3242
3243 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
3244 if (!(strcasecmp(rl_iter->name, rule_name))) {
3245 rule_exists = 1;
3246 new_rl = rl_iter;
3247 break;
3248 }
3249 }
3250 if (!rule_exists) {
3251 if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
3252 ast_config_destroy(cfg);
3253 return -1;
3254 }
3255 ast_copy_string(new_rl->name, rule_name, sizeof(new_rl->name));
3257 }
3258 timestr = ast_variable_retrieve(cfg, rulecat, "time");
3259 if (!(timestr) || sscanf(timestr, "%30d", &penaltychangetime) != 1) {
3260 ast_log(LOG_NOTICE, "Failed to parse time (%s) for one of the %s rules, skipping it\n",
3261 (ast_strlen_zero(timestr) ? "invalid value" : timestr), rule_name);
3262 continue;
3263 }
3264 if (!(new_penalty_rule = ast_calloc(1, sizeof(*new_penalty_rule)))) {
3265 ast_config_destroy(cfg);
3266 return -1;
3267 }
3268 if (!(maxstr = ast_variable_retrieve(cfg, rulecat, "max_penalty")) ||
3269 ast_strlen_zero(maxstr) || sscanf(maxstr, "%30d", &max_penalty) != 1) {
3270 max_penalty = 0;
3271 max_relative = 1;
3272 } else {
3273 if (*maxstr == '+' || *maxstr == '-') {
3274 max_relative = 1;
3275 }
3276 }
3277 if (!(minstr = ast_variable_retrieve(cfg, rulecat, "min_penalty")) ||
3278 ast_strlen_zero(minstr) || sscanf(minstr, "%30d", &min_penalty) != 1) {
3279 min_penalty = 0;
3280 min_relative = 1;
3281 } else {
3282 if (*minstr == '+' || *minstr == '-') {
3283 min_relative = 1;
3284 }
3285 }
3286 if (!(raisestr = ast_variable_retrieve(cfg, rulecat, "raise_penalty")) ||
3287 ast_strlen_zero(raisestr) || sscanf(raisestr, "%30d", &raise_penalty) != 1) {
3288 raise_penalty = 0;
3289 raise_relative = 1;
3290 } else {
3291 if (*raisestr == '+' || *raisestr == '-') {
3292 raise_relative = 1;
3293 }
3294 }
3295 new_penalty_rule->time = penaltychangetime;
3296 new_penalty_rule->max_relative = max_relative;
3297 new_penalty_rule->max_value = max_penalty;
3298 new_penalty_rule->min_relative = min_relative;
3299 new_penalty_rule->min_value = min_penalty;
3300 new_penalty_rule->raise_relative = raise_relative;
3301 new_penalty_rule->raise_value = raise_penalty;
3302 AST_LIST_TRAVERSE_SAFE_BEGIN(&new_rl->rules, pr_iter, list) {
3303 if (new_penalty_rule->time < pr_iter->time) {
3304 AST_LIST_INSERT_BEFORE_CURRENT(new_penalty_rule, list);
3305 inserted = 1;
3306 }
3307 }
3309 if (!inserted) {
3310 AST_LIST_INSERT_TAIL(&new_rl->rules, new_penalty_rule, list);
3311 }
3312 }
3313
3314 ast_config_destroy(cfg);
3315 return 0;
3316}
3317
3318static void parse_empty_options(const char *value, enum empty_conditions *empty, int joinempty)
3319{
3320 char *value_copy = ast_strdupa(value);
3321 char *option = NULL;
3322 while ((option = strsep(&value_copy, ","))) {
3323 if (!strcasecmp(option, "paused")) {
3324 *empty |= QUEUE_EMPTY_PAUSED;
3325 } else if (!strcasecmp(option, "penalty")) {
3326 *empty |= QUEUE_EMPTY_PENALTY;
3327 } else if (!strcasecmp(option, "inuse")) {
3328 *empty |= QUEUE_EMPTY_INUSE;
3329 } else if (!strcasecmp(option, "ringing")) {
3330 *empty |= QUEUE_EMPTY_RINGING;
3331 } else if (!strcasecmp(option, "invalid")) {
3332 *empty |= QUEUE_EMPTY_INVALID;
3333 } else if (!strcasecmp(option, "wrapup")) {
3334 *empty |= QUEUE_EMPTY_WRAPUP;
3335 } else if (!strcasecmp(option, "unavailable")) {
3336 *empty |= QUEUE_EMPTY_UNAVAILABLE;
3337 } else if (!strcasecmp(option, "unknown")) {
3338 *empty |= QUEUE_EMPTY_UNKNOWN;
3339 } else if (!strcasecmp(option, "loose")) {
3341 } else if (!strcasecmp(option, "strict")) {
3343 } else if ((ast_false(option) && joinempty) || (ast_true(option) && !joinempty)) {
3345 } else if ((ast_false(option) && !joinempty) || (ast_true(option) && joinempty)) {
3346 *empty = 0;
3347 } else {
3348 ast_log(LOG_WARNING, "Unknown option %s for '%s'\n", option, joinempty ? "joinempty" : "leavewhenempty");
3349 }
3350 }
3351}
3352
3353/*! \brief Configure a queue parameter.
3354 *
3355 * The failunknown flag is set for config files (and static realtime) to show
3356 * errors for unknown parameters. It is cleared for dynamic realtime to allow
3357 * extra fields in the tables.
3358 * \note For error reporting, line number is passed for .conf static configuration,
3359 * for Realtime queues, linenum is -1.
3360*/
3361static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
3362{
3363 if (!strcasecmp(param, "musicclass") ||
3364 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
3365 ast_string_field_set(q, moh, val);
3366 } else if (!strcasecmp(param, "announce")) {
3367 ast_string_field_set(q, announce, val);
3368 } else if (!strcasecmp(param, "context")) {
3370 } else if (!strcasecmp(param, "timeout")) {
3371 q->timeout = atoi(val);
3372 if (q->timeout < 0) {
3374 }
3375 } else if (!strcasecmp(param, "ringinuse")) {
3376 q->ringinuse = ast_true(val);
3377 } else if (!strcasecmp(param, "setinterfacevar")) {
3379 } else if (!strcasecmp(param, "setqueuevar")) {
3380 q->setqueuevar = ast_true(val);
3381 } else if (!strcasecmp(param, "setqueueentryvar")) {
3383 } else if (!strcasecmp(param, "monitor-format")) {
3384 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
3385 } else if (!strcasecmp(param, "membergosub")) {
3386 ast_string_field_set(q, membergosub, val);
3387 } else if (!strcasecmp(param, "queue-youarenext")) {
3388 ast_string_field_set(q, sound_next, val);
3389 } else if (!strcasecmp(param, "queue-thereare")) {
3390 ast_string_field_set(q, sound_thereare, val);
3391 } else if (!strcasecmp(param, "queue-callswaiting")) {
3392 ast_string_field_set(q, sound_calls, val);
3393 } else if (!strcasecmp(param, "queue-quantity1")) {
3394 ast_string_field_set(q, queue_quantity1, val);
3395 } else if (!strcasecmp(param, "queue-quantity2")) {
3396 ast_string_field_set(q, queue_quantity2, val);
3397 } else if (!strcasecmp(param, "queue-holdtime")) {
3398 ast_string_field_set(q, sound_holdtime, val);
3399 } else if (!strcasecmp(param, "queue-minutes")) {
3400 ast_string_field_set(q, sound_minutes, val);
3401 } else if (!strcasecmp(param, "queue-minute")) {
3402 ast_string_field_set(q, sound_minute, val);
3403 } else if (!strcasecmp(param, "queue-seconds")) {
3404 ast_string_field_set(q, sound_seconds, val);
3405 } else if (!strcasecmp(param, "queue-thankyou")) {
3406 ast_string_field_set(q, sound_thanks, val);
3407 } else if (!strcasecmp(param, "queue-callerannounce")) {
3408 ast_string_field_set(q, sound_callerannounce, val);
3409 } else if (!strcasecmp(param, "queue-reporthold")) {
3410 ast_string_field_set(q, sound_reporthold, val);
3411 } else if (!strcasecmp(param, "announce-frequency")) {
3412 q->announcefrequency = atoi(val);
3413 } else if (!strcasecmp(param, "announce-to-first-user")) {
3415 } else if (!strcasecmp(param, "min-announce-frequency")) {
3416 q->minannouncefrequency = atoi(val);
3417 ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name);
3418 } else if (!strcasecmp(param, "announce-round-seconds")) {
3419 q->roundingseconds = atoi(val);
3420 /* Rounding to any other values just doesn't make sense... */
3421 if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10
3422 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) {
3423 if (linenum >= 0) {
3424 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
3425 "using 0 instead for queue '%s' at line %d of queues.conf\n",
3426 val, param, q->name, linenum);
3427 } else {
3428 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
3429 "using 0 instead for queue '%s'\n", val, param, q->name);
3430 }
3431 q->roundingseconds=0;
3432 }
3433 } else if (!strcasecmp(param, "announce-holdtime")) {
3434 if (!strcasecmp(val, "once")) {
3436 } else if (ast_true(val)) {
3438 } else {
3439 q->announceholdtime = 0;
3440 }
3441 } else if (!strcasecmp(param, "announce-position")) {
3442 if (!strcasecmp(val, "limit")) {
3444 } else if (!strcasecmp(val, "more")) {
3446 } else if (ast_true(val)) {
3448 } else {
3450 }
3451 } else if (!strcasecmp(param, "announce-position-only-up")) {
3453 } else if (!strcasecmp(param, "announce-position-limit")) {
3454 q->announcepositionlimit = atoi(val);
3455 } else if (!strcasecmp(param, "periodic-announce")) {
3456 if (strchr(val, ',')) {
3457 char *s, *buf = ast_strdupa(val);
3458 unsigned int i = 0;
3459
3460 while ((s = strsep(&buf, ",|"))) {
3461 if (!q->sound_periodicannounce[i]) {
3463 }
3464 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s);
3465 i++;
3466 if (i == MAX_PERIODIC_ANNOUNCEMENTS) {
3467 break;
3468 }
3469 }
3470 q->numperiodicannounce = i;
3471 } else {
3472 ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val);
3473 q->numperiodicannounce = 1;
3474 }
3475 } else if (!strcasecmp(param, "periodic-announce-startdelay")) {
3477 } else if (!strcasecmp(param, "periodic-announce-frequency")) {
3478 q->periodicannouncefrequency = atoi(val);
3479 } else if (!strcasecmp(param, "relative-periodic-announce")) {
3481 } else if (!strcasecmp(param, "random-periodic-announce")) {
3483 } else if (!strcasecmp(param, "retry")) {
3484 q->retry = atoi(val);
3485 if (q->retry <= 0) {
3486 q->retry = DEFAULT_RETRY;
3487 }
3488 } else if (!strcasecmp(param, "wrapuptime")) {
3489 q->wrapuptime = atoi(val);
3490 } else if (!strcasecmp(param, "penaltymemberslimit")) {
3491 if ((sscanf(val, "%10d", &q->penaltymemberslimit) != 1)) {
3492 q->penaltymemberslimit = 0;
3493 }
3494 } else if (!strcasecmp(param, "autofill")) {
3495 q->autofill = ast_true(val);
3496 } else if (!strcasecmp(param, "autopause")) {
3498 } else if (!strcasecmp(param, "autopausedelay")) {
3499 q->autopausedelay = atoi(val);
3500 } else if (!strcasecmp(param, "autopausebusy")) {
3502 } else if (!strcasecmp(param, "autopauseunavail")) {
3504 } else if (!strcasecmp(param, "maxlen")) {
3505 q->maxlen = atoi(val);
3506 if (q->maxlen < 0) {
3507 q->maxlen = 0;
3508 }
3509 } else if (!strcasecmp(param, "servicelevel")) {
3510 q->servicelevel= atoi(val);
3511 } else if (!strcasecmp(param, "strategy")) {
3512 int strategy;
3513
3514 /* We are a static queue and already have set this, no need to do it again */
3515 if (failunknown) {
3516 return;
3517 }
3519 if (strategy < 0) {
3520 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
3521 val, q->name);
3523 }
3524 if (strategy == q->strategy) {
3525 return;
3526 }
3528 ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n");
3529 return;
3530 }
3531 q->strategy = strategy;
3532 } else if (!strcasecmp(param, "joinempty")) {
3534 } else if (!strcasecmp(param, "leavewhenempty")) {
3536 } else if (!strcasecmp(param, "reportholdtime")) {
3538 } else if (!strcasecmp(param, "memberdelay")) {
3539 q->memberdelay = atoi(val);
3540 } else if (!strcasecmp(param, "weight")) {
3541 q->weight = atoi(val);
3542 } else if (!strcasecmp(param, "timeoutrestart")) {
3544 } else if (!strcasecmp(param, "defaultrule")) {
3545 ast_string_field_set(q, defaultrule, val);
3546 } else if (!strcasecmp(param, "timeoutpriority")) {
3547 if (!strcasecmp(val, "conf")) {
3549 } else {
3551 }
3552 } else if (!strcasecmp(param, "log-restricted-caller-id")) {
3554 } else if (failunknown) {
3555 if (linenum >= 0) {
3556 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
3557 q->name, param, linenum);
3558 } else {
3559 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
3560 }
3561 }
3562}
3563
3564
3565#define QUEUE_PAUSED_DEVSTATE AST_DEVICE_INUSE
3566#define QUEUE_UNPAUSED_DEVSTATE AST_DEVICE_NOT_INUSE
3567#define QUEUE_UNKNOWN_PAUSED_DEVSTATE AST_DEVICE_NOT_INUSE
3568
3569/*! \internal
3570 * \brief If adding a single new member to a queue, use this function instead of ao2_linking.
3571 * This adds round robin queue position data for a fresh member as well as links it.
3572 * \param queue Which queue the member is being added to
3573 * \param mem Which member is being added to the queue
3574 */
3575static void member_add_to_queue(struct call_queue *queue, struct member *mem)
3576{
3577 ao2_lock(queue->members);
3578 mem->queuepos = ao2_container_count(queue->members);
3579 ao2_link(queue->members, mem);
3581 AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", queue->name, mem->interface);
3582 ao2_unlock(queue->members);
3583}
3584
3585/*! \internal
3586 * \brief If removing a single member from a queue, use this function instead of ao2_unlinking.
3587 * This will perform round robin queue position reordering for the remaining members.
3588 * \param queue Which queue the member is being removed from
3589 * \param mem Which member is being removed from the queue
3590 */
3591static void member_remove_from_queue(struct call_queue *queue, struct member *mem)
3592{
3594 ao2_lock(queue->members);
3597 ao2_unlink(queue->members, mem);
3598 ao2_unlock(queue->members);
3599}
3600
3601/*!
3602 * \brief Find rt member record to update otherwise create one.
3603 *
3604 * Search for member in queue, if found update penalty/paused state,
3605 * if no member exists create one flag it as a RT member and add to queue member list.
3606*/
3607static void rt_handle_member_record(struct call_queue *q, char *category, struct ast_config *member_config)
3608{
3609 struct member *m;
3610 struct ao2_iterator mem_iter;
3611 int penalty = 0;
3612 int paused = 0;
3613 int found = 0;
3614 int wrapuptime = 0;
3615 int ringinuse = q->ringinuse;
3616
3617 const char *config_val;
3618 const char *interface = ast_variable_retrieve(member_config, category, "interface");
3619 const char *rt_uniqueid = ast_variable_retrieve(member_config, category, "uniqueid");
3620 const char *membername = S_OR(ast_variable_retrieve(member_config, category, "membername"), interface);
3621 const char *state_interface = S_OR(ast_variable_retrieve(member_config, category, "state_interface"), interface);
3622 const char *penalty_str = ast_variable_retrieve(member_config, category, "penalty");
3623 const char *paused_str = ast_variable_retrieve(member_config, category, "paused");
3624 const char *wrapuptime_str = ast_variable_retrieve(member_config, category, "wrapuptime");
3625 const char *reason_paused = ast_variable_retrieve(member_config, category, "reason_paused");
3626
3627 if (ast_strlen_zero(rt_uniqueid)) {
3628 ast_log(LOG_WARNING, "Realtime field 'uniqueid' is empty for member %s\n",
3629 S_OR(membername, "NULL"));
3630 return;
3631 }
3632
3633 if (ast_strlen_zero(interface)) {
3634 ast_log(LOG_WARNING, "Realtime field 'interface' is empty for member %s\n",
3635 S_OR(membername, "NULL"));
3636 return;
3637 }
3638
3639 if (penalty_str) {
3640 penalty = atoi(penalty_str);
3641 if ((penalty < 0) && negative_penalty_invalid) {
3642 return;
3643 } else if (penalty < 0) {
3644 penalty = 0;
3645 }
3646 }
3647
3648 if (paused_str) {
3649 paused = atoi(paused_str);
3650 if (paused < 0) {
3651 paused = 0;
3652 }
3653 }
3654
3655 if (wrapuptime_str) {
3656 wrapuptime = atoi(wrapuptime_str);
3657 if (wrapuptime < 0) {
3658 wrapuptime = 0;
3659 }
3660 }
3661
3662 if ((config_val = ast_variable_retrieve(member_config, category, realtime_ringinuse_field))) {
3663 if (ast_true(config_val)) {
3664 ringinuse = 1;
3665 } else if (ast_false(config_val)) {
3666 ringinuse = 0;
3667 } else {
3668 ast_log(LOG_WARNING, "Invalid value of '%s' field for %s in queue '%s'\n", realtime_ringinuse_field, interface, q->name);
3669 }
3670 }
3671
3672 /* Find member by realtime uniqueid and update */
3673 mem_iter = ao2_iterator_init(q->members, 0);
3674 while ((m = ao2_iterator_next(&mem_iter))) {
3675 if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) {
3676 m->dead = 0; /* Do not delete this one. */
3677 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
3678 if (paused_str) {
3679 m->paused = paused;
3680 if (paused && m->lastpause == 0) {
3681 time(&m->lastpause); /* XXX: Should this come from realtime? */
3682 }
3684 AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", q->name, m->interface);
3685 }
3686 if (strcasecmp(state_interface, m->state_interface)) {
3687 ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
3688 }
3689 m->penalty = penalty;
3690 m->ringinuse = ringinuse;
3691 m->wrapuptime = wrapuptime;
3693 ast_copy_string(m->reason_paused, S_OR(reason_paused, ""), sizeof(m->reason_paused));
3694 }
3695 found = 1;
3696 ao2_ref(m, -1);
3697 break;
3698 }
3699 ao2_ref(m, -1);
3700 }
3701 ao2_iterator_destroy(&mem_iter);
3702
3703 /* Create a new member */
3704 if (!found) {
3705 if ((m = create_queue_member(interface, membername, penalty, paused, state_interface, ringinuse, wrapuptime))) {
3706 m->dead = 0;
3707 m->realtime = 1;
3708 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
3709 if (!ast_strlen_zero(reason_paused)) {
3710 ast_copy_string(m->reason_paused, reason_paused, sizeof(m->reason_paused));
3711 }
3713 ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
3714 } else {
3715 ast_queue_log(q->name, "REALTIME", m->membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
3716 }
3717 member_add_to_queue(q, m);
3718 ao2_ref(m, -1);
3719 m = NULL;
3720 }
3721 }
3722}
3723
3724/*! \brief Iterate through queue's member list and delete them */
3725static void free_members(struct call_queue *q, int all)
3726{
3727 /* Free non-dynamic members */
3728 struct member *cur;
3729 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
3730
3731 while ((cur = ao2_iterator_next(&mem_iter))) {
3732 if (all || !cur->dynamic) {
3734 }
3735 ao2_ref(cur, -1);
3736 }
3737 ao2_iterator_destroy(&mem_iter);
3738}
3739
3740/*! \brief Free queue's member list then its string fields */
3741static void destroy_queue(void *obj)
3742{
3743 struct call_queue *q = obj;
3744 int i;
3745
3746 free_members(q, 1);
3748 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
3749 if (q->sound_periodicannounce[i]) {
3751 }
3752 }
3753 ao2_ref(q->members, -1);
3754}
3755
3756static struct call_queue *alloc_queue(const char *queuename)
3757{
3758 struct call_queue *q;
3759
3760 if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) {
3761 if (ast_string_field_init(q, 64)) {
3762 queue_t_unref(q, "String field allocation failed");
3763 return NULL;
3764 }
3765 ast_string_field_set(q, name, queuename);
3766 }
3767 return q;
3768}
3769
3770/*!
3771 * \brief Reload a single queue via realtime.
3772 *
3773 * Check for statically defined queue first, check if deleted RT queue,
3774 * check for new RT queue, if queue vars are not defined init them with defaults.
3775 * reload RT queue vars, set RT queue members dead and reload them, return finished queue.
3776 * \retval the queue,
3777 * \retval NULL if it doesn't exist.
3778 * \note Should be called with the "queues" container locked.
3779*/
3780static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
3781{
3782 struct ast_variable *v;
3783 struct call_queue *q, tmpq = {
3784 .name = queuename,
3785 };
3786 struct member *m;
3787 struct ao2_iterator mem_iter;
3788 char *category = NULL;
3789 const char *tmp_name;
3790 char *tmp;
3791 char tmpbuf[64]; /* Must be longer than the longest queue param name. */
3792
3793 /* Static queues override realtime. */
3794 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Check if static queue exists"))) {
3795 ao2_lock(q);
3796 if (!q->realtime) {
3797 if (q->dead) {
3798 ao2_unlock(q);
3799 queue_t_unref(q, "Queue is dead; can't return it");
3800 return NULL;
3801 }
3802 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
3803 ao2_unlock(q);
3804 return q;
3805 }
3806 } else if (!member_config) {
3807 /* Not found in the list, and it's not realtime ... */
3808 return NULL;
3809 }
3810 /* Check if queue is defined in realtime. */
3811 if (!queue_vars) {
3812 /* Delete queue from in-core list if it has been deleted in realtime. */
3813 if (q) {
3814 /*! \note Hmm, can't seem to distinguish a DB failure from a not
3815 found condition... So we might delete an in-core queue
3816 in case of DB failure. */
3817 ast_debug(1, "Queue %s not found in realtime.\n", queuename);
3818
3819 q->dead = 1;
3820 /* Delete if unused (else will be deleted when last caller leaves). */
3821 queues_t_unlink(queues, q, "Unused; removing from container");
3822 ao2_unlock(q);
3823 queue_t_unref(q, "Queue is dead; can't return it");
3824 }
3825 return NULL;
3826 }
3827
3828 /* Create a new queue if an in-core entry does not exist yet. */
3829 if (!q) {
3830 struct ast_variable *tmpvar = NULL;
3831 if (!(q = alloc_queue(queuename))) {
3832 return NULL;
3833 }
3834 ao2_lock(q);
3835 clear_queue(q);
3836 q->realtime = 1;
3837 /*Before we initialize the queue, we need to set the strategy, so that linear strategy
3838 * will allocate the members properly
3839 */
3840 for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) {
3841 if (!strcasecmp(tmpvar->name, "strategy")) {
3842 q->strategy = strat2int(tmpvar->value);
3843 if (q->strategy < 0) {
3844 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
3845 tmpvar->value, q->name);
3847 }
3848 break;
3849 }
3850 }
3851 /* We traversed all variables and didn't find a strategy */
3852 if (!tmpvar) {
3854 }
3855 queues_t_link(queues, q, "Add queue to container");
3856 }
3857 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
3858
3859 memset(tmpbuf, 0, sizeof(tmpbuf));
3860 for (v = queue_vars; v; v = v->next) {
3861 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
3862 if (strchr(v->name, '_')) {
3863 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
3864 tmp_name = tmpbuf;
3865 tmp = tmpbuf;
3866 while ((tmp = strchr(tmp, '_'))) {
3867 *tmp++ = '-';
3868 }
3869 } else {
3870 tmp_name = v->name;
3871 }
3872
3873 /* NULL values don't get returned from realtime; blank values should
3874 * still get set. If someone doesn't want a value to be set, they
3875 * should set the realtime column to NULL, not blank. */
3876 queue_set_param(q, tmp_name, v->value, -1, 0);
3877 }
3878
3879 /* Temporarily set realtime members dead so we can detect deleted ones. */
3880 mem_iter = ao2_iterator_init(q->members, 0);
3881 while ((m = ao2_iterator_next(&mem_iter))) {
3882 if (m->realtime) {
3883 m->dead = 1;
3884 }
3885 ao2_ref(m, -1);
3886 }
3887 ao2_iterator_destroy(&mem_iter);
3888
3889 while ((category = ast_category_browse(member_config, category))) {
3890 rt_handle_member_record(q, category, member_config);
3891 }
3892
3893 /* Delete all realtime members that have been deleted in DB. */
3894 mem_iter = ao2_iterator_init(q->members, 0);
3895 while ((m = ao2_iterator_next(&mem_iter))) {
3896 if (m->dead) {
3898 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
3899 } else {
3900 ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
3901 }
3903 }
3904 ao2_ref(m, -1);
3905 }
3906 ao2_iterator_destroy(&mem_iter);
3907
3908 ao2_unlock(q);
3909
3910 return q;
3911}
3912
3913/*!
3914 * note */
3915
3916/*!
3917 * \internal
3918 * \brief Returns reference to the named queue. If the queue is realtime, it will load the queue as well.
3919 * \param queuename - name of the desired queue
3920 *
3921 * \retval the queue
3922 * \retval NULL if it doesn't exist
3923 */
3924static struct call_queue *find_load_queue_rt_friendly(const char *queuename)
3925{
3926 struct ast_variable *queue_vars;
3927 struct ast_config *member_config = NULL;
3928 struct call_queue *q = NULL, tmpq = {
3929 .name = queuename,
3930 };
3931 int prev_weight = 0;
3932
3933 /* Find the queue in the in-core list first. */
3934 q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Look for queue in memory first");
3935
3936 if (!q || q->realtime) {
3937 /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all
3938 queue operations while waiting for the DB.
3939
3940 This will be two separate database transactions, so we might
3941 see queue parameters as they were before another process
3942 changed the queue and member list as it was after the change.
3943 Thus we might see an empty member list when a queue is
3944 deleted. In practise, this is unlikely to cause a problem. */
3945
3946 queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL);
3947 if (queue_vars) {
3948 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL);
3949 if (!member_config) {
3950 ast_debug(1, "No queue_members defined in config extconfig.conf\n");
3951 member_config = ast_config_new();
3952 }
3953 }
3954 if (q) {
3955 prev_weight = q->weight ? 1 : 0;
3956 queue_t_unref(q, "Need to find realtime queue");
3957 }
3958
3959 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
3960 ast_config_destroy(member_config);
3961 ast_variables_destroy(queue_vars);
3962
3963 /* update the use_weight value if the queue's has gained or lost a weight */
3964 if (q) {
3965 if (!q->weight && prev_weight) {
3967 }
3968 if (q->weight && !prev_weight) {
3970 }
3971 }
3972 /* Other cases will end up with the proper value for use_weight */
3973 } else {
3975 }
3976 return q;
3977}
3978
3979/*!
3980 * \internal
3981 * \brief Load queues and members from realtime.
3982 *
3983 * \param queuename - name of the desired queue to load or empty if need to load all queues
3984*/
3985static void load_realtime_queues(const char *queuename)
3986{
3987 struct ast_config *cfg = NULL;
3988 char *category = NULL;
3989 const char *name = NULL;
3990 struct call_queue *q = NULL;
3991
3992 if (!ast_check_realtime("queues")) {
3993 return;
3994 }
3995
3996 if (ast_strlen_zero(queuename)) {
3997 if ((cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL))) {
3998 while ((category = ast_category_browse(cfg, category))) {
3999 name = ast_variable_retrieve(cfg, category, "name");
4001 queue_unref(q);
4002 }
4003 }
4004 ast_config_destroy(cfg);
4005 }
4006 } else {
4007 if ((q = find_load_queue_rt_friendly(queuename))) {
4008 queue_unref(q);
4009 }
4010 }
4011}
4012
4013static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
4014{
4015 int ret = -1;
4016
4017 if (ast_strlen_zero(mem->rt_uniqueid)) {
4018 return ret;
4019 }
4020
4021 if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) >= 0) {
4022 ret = 0;
4023 }
4024
4025 return ret;
4026}
4027
4028
4030{
4031 struct ast_config *member_config = NULL;
4032 struct member *m;
4033 char *category = NULL;
4034 struct ao2_iterator mem_iter;
4035
4036 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , SENTINEL))) {
4037 /* This queue doesn't have realtime members. If the queue still has any realtime
4038 * members in memory, they need to be removed.
4039 */
4040 ao2_lock(q);
4041 mem_iter = ao2_iterator_init(q->members, 0);
4042 while ((m = ao2_iterator_next(&mem_iter))) {
4043 if (m->realtime) {
4045 }
4046 ao2_ref(m, -1);
4047 }
4048 ao2_iterator_destroy(&mem_iter);
4049 ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name);
4050 ao2_unlock(q);
4051 return;
4052 }
4053
4054 ao2_lock(q);
4055
4056 /* Temporarily set realtime members dead so we can detect deleted ones.*/
4057 mem_iter = ao2_iterator_init(q->members, 0);
4058 while ((m = ao2_iterator_next(&mem_iter))) {
4059 if (m->realtime) {
4060 m->dead = 1;
4061 }
4062 ao2_ref(m, -1);
4063 }
4064 ao2_iterator_destroy(&mem_iter);
4065
4066 while ((category = ast_category_browse(member_config, category))) {
4067 rt_handle_member_record(q, category, member_config);
4068 }
4069
4070 /* Delete all realtime members that have been deleted in DB. */
4071 mem_iter = ao2_iterator_init(q->members, 0);
4072 while ((m = ao2_iterator_next(&mem_iter))) {
4073 if (m->dead) {
4075 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
4076 } else {
4077 ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
4078 }
4080 }
4081 ao2_ref(m, -1);
4082 }
4083 ao2_iterator_destroy(&mem_iter);
4084 ao2_unlock(q);
4085 ast_config_destroy(member_config);
4086}
4087
4088static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
4089{
4090 struct call_queue *q;
4091 struct queue_ent *cur, *prev = NULL;
4092 int res = -1;
4093 int pos = 0;
4094 int inserted = 0;
4095
4096 if (!(q = find_load_queue_rt_friendly(queuename))) {
4097 return res;
4098 }
4099 ao2_lock(q);
4100
4101 /* This is our one */
4102 if (q->joinempty) {
4103 int status = 0;
4104 if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, qe->raise_penalty, q->joinempty, 0))) {
4105 *reason = QUEUE_JOINEMPTY;
4106 ao2_unlock(q);
4107 queue_t_unref(q, "Done with realtime queue");
4108 return res;
4109 }
4110 }
4111 if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen)) {
4112 *reason = QUEUE_FULL;
4113 } else if (*reason == QUEUE_UNKNOWN) {
4114 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4115
4116 /* There's space for us, put us at the right position inside
4117 * the queue.
4118 * Take into account the priority of the calling user */
4119 inserted = 0;
4120 prev = NULL;
4121 cur = q->head;
4122 while (cur) {
4123 /* We have higher priority than the current user, enter
4124 * before him, after all the other users with priority
4125 * higher or equal to our priority. */
4126 if ((!inserted) && (qe->prio > cur->prio)) {
4127 insert_entry(q, prev, qe, &pos);
4128 inserted = 1;
4129 }
4130 /* <= is necessary for the position comparison because it may not be possible to enter
4131 * at our desired position since higher-priority callers may have taken the position we want
4132 */
4133 if (!inserted && (qe->prio >= cur->prio) && position && (position <= pos + 1)) {
4134 insert_entry(q, prev, qe, &pos);
4135 inserted = 1;
4136 /*pos is incremented inside insert_entry, so don't need to add 1 here*/
4137 if (position < pos) {
4138 ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos);
4139 }
4140 }
4141 cur->pos = ++pos;
4142 prev = cur;
4143 cur = cur->next;
4144 }
4145 /* No luck, join at the end of the queue */
4146 if (!inserted) {
4147 insert_entry(q, prev, qe, &pos);
4148 }
4149 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
4150 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
4151 ast_copy_string(qe->context, q->context, sizeof(qe->context));
4152 q->count++;
4153 if (q->count == 1) {
4155 }
4156
4157 res = 0;
4158
4159 blob = ast_json_pack("{s: s, s: i, s: i}",
4160 "Queue", q->name,
4161 "Position", qe->pos,
4162 "Count", q->count);
4163 ast_channel_publish_cached_blob(qe->chan, queue_caller_join_type(), blob);
4164 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, ast_channel_name(qe->chan), qe->pos );
4165 }
4166 ao2_unlock(q);
4167 queue_t_unref(q, "Done with realtime queue");
4168
4169 return res;
4170}
4171
4172static int play_file(struct ast_channel *chan, const char *filename)
4173{
4174 int res;
4175
4176 if (ast_strlen_zero(filename)) {
4177 return 0;
4178 }
4179
4180 if (!ast_fileexists(filename, NULL, ast_channel_language(chan))) {
4181 return 0;
4182 }
4183
4185
4186 res = ast_streamfile(chan, filename, ast_channel_language(chan));
4187 if (!res) {
4189 }
4190
4192
4193 return res;
4194}
4195
4196/*!
4197 * \brief Check for valid exit from queue via goto
4198 * \retval 0 if failure
4199 * \retval 1 if successful
4200*/
4201static int valid_exit(struct queue_ent *qe, char digit)
4202{
4203 int digitlen = strlen(qe->digits);
4204
4205 /* Prevent possible buffer overflow */
4206 if (digitlen < sizeof(qe->digits) - 2) {
4207 qe->digits[digitlen] = digit;
4208 qe->digits[digitlen + 1] = '\0';
4209 } else {
4210 qe->digits[0] = '\0';
4211 return 0;
4212 }
4213
4214 /* If there's no context to goto, short-circuit */
4215 if (ast_strlen_zero(qe->context)) {
4216 return 0;
4217 }
4218
4219 /* If the extension is bad, then reset the digits to blank */
4220 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1,
4222 qe->digits[0] = '\0';
4223 return 0;
4224 }
4225
4226 /* We have an exact match */
4227 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
4228 qe->valid_digits = 1;
4229 /* Return 1 on a successful goto */
4230 return 1;
4231 }
4232
4233 return 0;
4234}
4235
4236static int say_position(struct queue_ent *qe, int ringing)
4237{
4238 int res = 0, say_thanks = 0;
4239 long avgholdmins, avgholdsecs;
4240 time_t now;
4241
4242 /* Let minannouncefrequency seconds pass between the start of each position announcement */
4243 time(&now);
4244 if ((now - qe->last_pos) < qe->parent->minannouncefrequency) {
4245 return 0;
4246 }
4247
4248 /* If either our position has changed, or we are over the freq timer, say position */
4249 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency)) {
4250 return 0;
4251 }
4252
4253 /* Only announce if the caller's queue position has improved since last time */
4254 if (qe->parent->announceposition_only_up && qe->last_pos_said <= qe->pos) {
4255 return 0;
4256 }
4257
4258 if (ringing) {
4259 ast_indicate(qe->chan,-1);
4260 } else {
4261 ast_moh_stop(qe->chan);
4262 }
4263
4267 qe->pos <= qe->parent->announcepositionlimit)) {
4268 say_thanks = 1;
4269 /* Say we're next, if we are */
4270 if (qe->pos == 1) {
4271 res = play_file(qe->chan, qe->parent->sound_next);
4272 if (!res) {
4273 goto posout;
4274 }
4275 /* Say there are more than N callers */
4277 res = (
4278 play_file(qe->chan, qe->parent->queue_quantity1) ||
4280 ast_channel_language(qe->chan), NULL) || /* Needs gender */
4282 /* Say there are currently N callers waiting */
4283 } else {
4284 res = (
4285 play_file(qe->chan, qe->parent->sound_thereare) ||
4287 ast_channel_language(qe->chan), "n") || /* Needs gender */
4288 play_file(qe->chan, qe->parent->sound_calls));
4289 }
4290 if (res) {
4291 goto playout;
4292 }
4293 }
4294 /* Round hold time to nearest minute */
4295 avgholdmins = labs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
4296
4297 /* If they have specified a rounding then round the seconds as well */
4298 if (qe->parent->roundingseconds) {
4299 avgholdsecs = (labs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
4300 avgholdsecs *= qe->parent->roundingseconds;
4301 } else {
4302 avgholdsecs = 0;
4303 }
4304
4305 ast_verb(3, "Hold time for %s is %ld minute(s) %ld seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
4306
4307 /* If the hold time is >1 min, if it's enabled, and if it's not
4308 supposed to be only once and we have already said it, say it */
4309 if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime &&
4312 say_thanks = 1;
4313 res = play_file(qe->chan, qe->parent->sound_holdtime);
4314 if (res) {
4315 goto playout;
4316 }
4317
4318 if (avgholdmins >= 1) {
4319 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, ast_channel_language(qe->chan), "n");
4320 if (res) {
4321 goto playout;
4322 }
4323
4324 if (avgholdmins == 1) {
4325 res = play_file(qe->chan, qe->parent->sound_minute);
4326 if (res) {
4327 goto playout;
4328 }
4329 } else {
4330 res = play_file(qe->chan, qe->parent->sound_minutes);
4331 if (res) {
4332 goto playout;
4333 }
4334 }
4335 }
4336 if (avgholdsecs >= 1) {
4337 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, ast_channel_language(qe->chan), "n");
4338 if (res) {
4339 goto playout;
4340 }
4341
4342 res = play_file(qe->chan, qe->parent->sound_seconds);
4343 if (res) {
4344 goto playout;
4345 }
4346 }
4347 }
4348
4349posout:
4350 if (qe->parent->announceposition) {
4351 ast_verb(3, "Told %s in %s their queue position (which was %d)\n",
4352 ast_channel_name(qe->chan), qe->parent->name, qe->pos);
4353 }
4354 if (say_thanks) {
4355 res = play_file(qe->chan, qe->parent->sound_thanks);
4356 }
4357playout:
4358
4359 if ((res > 0 && !valid_exit(qe, res))) {
4360 res = 0;
4361 }
4362
4363 /* Set our last_pos indicators */
4364 qe->last_pos = now;
4365 qe->last_pos_said = qe->pos;
4366
4367 /* Don't restart music on hold if we're about to exit the caller from the queue */
4368 if (!res) {
4369 if (ringing) {
4371 } else {
4372 ast_moh_start(qe->chan, qe->moh, NULL);
4373 }
4374 }
4375 return res;
4376}
4377
4378static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
4379{
4380 int oldvalue;
4381
4382 /* Calculate holdtime using an exponential average */
4383 /* Thanks to SRT for this contribution */
4384 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
4385
4386 ao2_lock(qe->parent);
4387 if ((qe->parent->callscompleted + qe->parent->callsabandoned) == 0) {
4388 qe->parent->holdtime = newholdtime;
4389 } else {
4390 oldvalue = qe->parent->holdtime;
4391 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
4392 }
4393 ao2_unlock(qe->parent);
4394}
4395
4396/*! \brief Caller leaving queue.
4397 *
4398 * Search the queue to find the leaving client, if found remove from queue
4399 * create manager event, move others up the queue.
4400*/
4401static void leave_queue(struct queue_ent *qe)
4402{
4403 struct call_queue *q;
4404 struct queue_ent *current, *prev = NULL;
4405 struct penalty_rule *pr_iter;
4406 int pos = 0;
4407
4408 if (!(q = qe->parent)) {
4409 return;
4410 }
4411 queue_t_ref(q, "Copy queue pointer from queue entry");
4412 ao2_lock(q);
4413
4414 prev = NULL;
4415 for (current = q->head; current; current = current->next) {
4416 if (current == qe) {
4417 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4418 char posstr[20];
4419 q->count--;
4420 if (!q->count) {
4422 }
4423
4424 blob = ast_json_pack("{s: s, s: i, s: i}",
4425 "Queue", q->name,
4426 "Position", qe->pos,
4427 "Count", q->count);
4428 ast_channel_publish_cached_blob(qe->chan, queue_caller_leave_type(), blob);
4429 ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, ast_channel_name(qe->chan));
4430 /* Take us out of the queue */
4431 if (prev) {
4432 prev->next = current->next;
4433 } else {
4434 q->head = current->next;
4435 }
4436 /* Free penalty rules */
4437 while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list))) {
4438 ast_free(pr_iter);
4439 }
4440 qe->pr = NULL;
4441 snprintf(posstr, sizeof(posstr), "%d", qe->pos);
4442 pbx_builtin_setvar_helper(qe->chan, "QUEUEPOSITION", posstr);
4443 } else {
4444 /* Renumber the people after us in the queue based on a new count */
4445 current->pos = ++pos;
4446 prev = current;
4447 }
4448 }
4449 ao2_unlock(q);
4450
4451 /*If the queue is a realtime queue, check to see if it's still defined in real time*/
4452 if (q->realtime) {
4453 struct ast_variable *var;
4454 if (!(var = ast_load_realtime("queues", "name", q->name, SENTINEL))) {
4455 q->dead = 1;
4456 } else {
4458 }
4459 }
4460
4461 if (q->dead) {
4462 /* It's dead and nobody is in it, so kill it */
4463 queues_t_unlink(queues, q, "Queue is now dead; remove it from the container");
4464 }
4465 /* unref the explicit ref earlier in the function */
4466 queue_t_unref(q, "Expire copied reference");
4467}
4468
4469/*!
4470 * \internal
4471 * \brief Destroy the given callattempt structure and free it.
4472 * \since 1.8
4473 *
4474 * \param doomed callattempt structure to destroy.
4475 */
4476static void callattempt_free(struct callattempt *doomed)
4477{
4478 if (doomed->member) {
4479 ao2_ref(doomed->member, -1);
4480 }
4482 ast_free(doomed->orig_chan_name);
4483 ast_free(doomed);
4484}
4485
4486static void publish_dial_end_event(struct ast_channel *in, struct callattempt *outgoing, struct ast_channel *exception, const char *status)
4487{
4488 struct callattempt *cur;
4489
4490 for (cur = outgoing; cur; cur = cur->q_next) {
4491 if (cur->chan && cur->chan != exception) {
4493 }
4494 }
4495}
4496
4497/*! \brief Hang up a list of outgoing calls */
4498static void hangupcalls(struct queue_ent *qe, struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere)
4499{
4500 struct callattempt *oo;
4501
4502 while (outgoing) {
4503 /* If someone else answered the call we should indicate this in the CANCEL */
4504 /* Hangup any existing lines we have open */
4505 if (outgoing->chan && (outgoing->chan != exception)) {
4506 if (exception || cancel_answered_elsewhere) {
4508 }
4509 ast_channel_publish_dial(qe->chan, outgoing->chan, outgoing->interface, "CANCEL");
4510
4511 /* When dialing channels it is possible that they may not ever
4512 * leave the not in use state (Local channels in particular) by
4513 * the time we cancel them. If this occurs but we know they were
4514 * dialed we explicitly remove them from the pending members
4515 * container so that subsequent call attempts occur.
4516 */
4517 if (outgoing->member->status == AST_DEVICE_NOT_INUSE) {
4519 }
4520
4521 ast_hangup(outgoing->chan);
4522 }
4523 oo = outgoing;
4524 outgoing = outgoing->q_next;
4526 callattempt_free(oo);
4527 }
4528}
4529
4530/*!
4531 * \brief Get the number of members available to accept a call.
4532 *
4533 * \note The queue passed in should be locked prior to this function call
4534 *
4535 * \param[in] q The queue for which we are counting the number of available members
4536 * \return Return the number of available members in queue q
4537 */
4539{
4540 struct member *mem;
4541 int avl = 0;
4542 struct ao2_iterator mem_iter;
4543
4544 mem_iter =