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