30b5ed67097ea4ed7dd4a30f2119d8cd99325bad
[asterisk/asterisk.git] / apps / app_queue.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, 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 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
73
74 #include <sys/time.h>
75 #include <sys/signal.h>
76 #include <netinet/in.h>
77 #include <ctype.h>
78
79 #include "asterisk/lock.h"
80 #include "asterisk/file.h"
81 #include "asterisk/channel.h"
82 #include "asterisk/pbx.h"
83 #include "asterisk/app.h"
84 #include "asterisk/linkedlists.h"
85 #include "asterisk/module.h"
86 #include "asterisk/translate.h"
87 #include "asterisk/say.h"
88 #include "asterisk/features.h"
89 #include "asterisk/musiconhold.h"
90 #include "asterisk/cli.h"
91 #include "asterisk/manager.h"
92 #include "asterisk/config.h"
93 #include "asterisk/monitor.h"
94 #include "asterisk/utils.h"
95 #include "asterisk/causes.h"
96 #include "asterisk/astdb.h"
97 #include "asterisk/devicestate.h"
98 #include "asterisk/stringfields.h"
99 #include "asterisk/astobj2.h"
100 #include "asterisk/strings.h"
101 #include "asterisk/global_datastores.h"
102 #include "asterisk/taskprocessor.h"
103 #include "asterisk/aoc.h"
104 #include "asterisk/callerid.h"
105 #include "asterisk/data.h"
106 #include "asterisk/term.h"
107 #include "asterisk/dial.h"
108 #include "asterisk/stasis_channels.h"
109 #include "asterisk/stasis_message_router.h"
110 #include "asterisk/bridge_after.h"
111
112 /* Define, to debug reference counts on queues, without debugging reference counts on queue members */
113 /* #define REF_DEBUG_ONLY_QUEUES */
114
115 /*!
116  * \par Please read before modifying this file.
117  * There are three locks which are regularly used
118  * throughout this file, the queue list lock, the lock
119  * for each individual queue, and the interface list lock.
120  * Please be extra careful to always lock in the following order
121  * 1) queue list lock
122  * 2) individual queue lock
123  * 3) interface list lock
124  * This order has sort of "evolved" over the lifetime of this
125  * application, but it is now in place this way, so please adhere
126  * to this order!
127  */
128
129 /*** DOCUMENTATION
130         <application name="Queue" language="en_US">
131                 <synopsis>
132                         Queue a call for a call queue.
133                 </synopsis>
134                 <syntax>
135                         <parameter name="queuename" required="true" />
136                         <parameter name="options">
137                                 <optionlist>
138                                         <option name="C">
139                                                 <para>Mark all calls as "answered elsewhere" when cancelled.</para>
140                                         </option>
141                                         <option name="c">
142                                                 <para>Continue in the dialplan if the callee hangs up.</para>
143                                         </option>
144                                         <option name="d">
145                                                 <para>data-quality (modem) call (minimum delay).</para>
146                                         </option>
147                                         <option name="F" argsep="^">
148                                                 <argument name="context" required="false" />
149                                                 <argument name="exten" required="false" />
150                                                 <argument name="priority" required="true" />
151                                                 <para>When the caller hangs up, transfer the <emphasis>called member</emphasis>
152                                                 to the specified destination and <emphasis>start</emphasis> execution at that location.</para>
153                                                 <note>
154                                                         <para>Any channel variables you want the called channel to inherit from the caller channel must be
155                                                         prefixed with one or two underbars ('_').</para>
156                                                 </note>
157                                         </option>
158                                         <option name="F">
159                                                 <para>When the caller hangs up, transfer the <emphasis>called member</emphasis> to the next priority of
160                                                 the current extension and <emphasis>start</emphasis> execution at that location.</para>
161                                                 <note>
162                                                         <para>Any channel variables you want the called channel to inherit from the caller channel must be
163                                                         prefixed with one or two underbars ('_').</para>
164                                                 </note>
165                                                 <note>
166                                                         <para>Using this option from a Macro() or GoSub() might not make sense as there would be no return points.</para>
167                                                 </note>
168                                         </option>
169                                         <option name="h">
170                                                 <para>Allow <emphasis>callee</emphasis> to hang up by pressing <literal>*</literal>.</para>
171                                         </option>
172                                         <option name="H">
173                                                 <para>Allow <emphasis>caller</emphasis> to hang up by pressing <literal>*</literal>.</para>
174                                         </option>
175                                         <option name="n">
176                                                 <para>No retries on the timeout; will exit this application and
177                                                 go to the next step.</para>
178                                         </option>
179                                         <option name="i">
180                                                 <para>Ignore call forward requests from queue members and do nothing
181                                                 when they are requested.</para>
182                                         </option>
183                                         <option name="I">
184                                                 <para>Asterisk will ignore any connected line update requests or any redirecting party
185                                                 update requests it may receive on this dial attempt.</para>
186                                         </option>
187                                         <option name="r">
188                                                 <para>Ring instead of playing MOH. Periodic Announcements are still made, if applicable.</para>
189                                         </option>
190                                         <option name="R">
191                                                 <para>Ring instead of playing MOH when a member channel is actually ringing.</para>
192                                         </option>
193                                         <option name="t">
194                                                 <para>Allow the <emphasis>called</emphasis> user to transfer the calling user.</para>
195                                         </option>
196                                         <option name="T">
197                                                 <para>Allow the <emphasis>calling</emphasis> user to transfer the call.</para>
198                                         </option>
199                                         <option name="w">
200                                                 <para>Allow the <emphasis>called</emphasis> user to write the conversation to
201                                                 disk via Monitor.</para>
202                                         </option>
203                                         <option name="W">
204                                                 <para>Allow the <emphasis>calling</emphasis> user to write the conversation to
205                                                 disk via Monitor.</para>
206                                         </option>
207                                         <option name="k">
208                                                 <para>Allow the <emphasis>called</emphasis> party to enable parking of the call by sending
209                                                 the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
210                                         </option>
211                                         <option name="K">
212                                                 <para>Allow the <emphasis>calling</emphasis> party to enable parking of the call by sending
213                                                 the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
214                                         </option>
215                                         <option name="x">
216                                                 <para>Allow the <emphasis>called</emphasis> user to write the conversation
217                                                 to disk via MixMonitor.</para>
218                                         </option>
219                                         <option name="X">
220                                                 <para>Allow the <emphasis>calling</emphasis> user to write the conversation to
221                                                 disk via MixMonitor.</para>
222                                         </option>
223                                 </optionlist>
224                         </parameter>
225                         <parameter name="URL">
226                                 <para><replaceable>URL</replaceable> will be sent to the called party if the channel supports it.</para>
227                         </parameter>
228                         <parameter name="announceoverride" />
229                         <parameter name="timeout">
230                                 <para>Will cause the queue to fail out after a specified number of
231                                 seconds, checked between each <filename>queues.conf</filename> <replaceable>timeout</replaceable> and
232                                 <replaceable>retry</replaceable> cycle.</para>
233                         </parameter>
234                         <parameter name="AGI">
235                                 <para>Will setup an AGI script to be executed on the calling party's channel once they are
236                                 connected to a queue member.</para>
237                         </parameter>
238                         <parameter name="macro">
239                                 <para>Will run a macro on the calling party's channel once they are connected to a queue member.</para>
240                         </parameter>
241                         <parameter name="gosub">
242                                 <para>Will run a gosub on the calling party's channel once they are connected to a queue member.</para>
243                         </parameter>
244                         <parameter name="rule">
245                                 <para>Will cause the queue's defaultrule to be overridden by the rule specified.</para>
246                         </parameter>
247                         <parameter name="position">
248                                 <para>Attempt to enter the caller into the queue at the numerical position specified. <literal>1</literal>
249                                 would attempt to enter the caller at the head of the queue, and <literal>3</literal> would attempt to place
250                                 the caller third in the queue.</para>
251                         </parameter>
252                 </syntax>
253                 <description>
254                         <para>In addition to transferring the call, a call may be parked and then picked
255                         up by another user.</para>
256                         <para>This application will return to the dialplan if the queue does not exist, or
257                         any of the join options cause the caller to not enter the queue.</para>
258                         <para>This application does not automatically answer and should be preceeded
259                         by an application such as Answer(), Progress(), or Ringing().</para>
260                         <para>This application sets the following channel variable upon completion:</para>
261                         <variablelist>
262                                 <variable name="QUEUESTATUS">
263                                         <para>The status of the call as a text string.</para>
264                                         <value name="TIMEOUT" />
265                                         <value name="FULL" />
266                                         <value name="JOINEMPTY" />
267                                         <value name="LEAVEEMPTY" />
268                                         <value name="JOINUNAVAIL" />
269                                         <value name="LEAVEUNAVAIL" />
270                                         <value name="CONTINUE" />
271                                 </variable>
272                         </variablelist>
273                 </description>
274                 <see-also>
275                         <ref type="application">Queue</ref>
276                         <ref type="application">QueueLog</ref>
277                         <ref type="application">AddQueueMember</ref>
278                         <ref type="application">RemoveQueueMember</ref>
279                         <ref type="application">PauseQueueMember</ref>
280                         <ref type="application">UnpauseQueueMember</ref>
281                         <ref type="function">QUEUE_VARIABLES</ref>
282                         <ref type="function">QUEUE_MEMBER</ref>
283                         <ref type="function">QUEUE_MEMBER_COUNT</ref>
284                         <ref type="function">QUEUE_EXISTS</ref>
285                         <ref type="function">QUEUE_WAITING_COUNT</ref>
286                         <ref type="function">QUEUE_MEMBER_LIST</ref>
287                         <ref type="function">QUEUE_MEMBER_PENALTY</ref>
288                 </see-also>
289         </application>
290         <application name="AddQueueMember" language="en_US">
291                 <synopsis>
292                         Dynamically adds queue members.
293                 </synopsis>
294                 <syntax>
295                         <parameter name="queuename" required="true" />
296                         <parameter name="interface" />
297                         <parameter name="penalty" />
298                         <parameter name="options" />
299                         <parameter name="membername" />
300                         <parameter name="stateinterface" />
301                 </syntax>
302                 <description>
303                         <para>Dynamically adds interface to an existing queue. If the interface is
304                         already in the queue it will return an error.</para>
305                         <para>This application sets the following channel variable upon completion:</para>
306                         <variablelist>
307                                 <variable name="AQMSTATUS">
308                                         <para>The status of the attempt to add a queue member as a text string.</para>
309                                         <value name="ADDED" />
310                                         <value name="MEMBERALREADY" />
311                                         <value name="NOSUCHQUEUE" />
312                                 </variable>
313                         </variablelist>
314                 </description>
315                 <see-also>
316                         <ref type="application">Queue</ref>
317                         <ref type="application">QueueLog</ref>
318                         <ref type="application">AddQueueMember</ref>
319                         <ref type="application">RemoveQueueMember</ref>
320                         <ref type="application">PauseQueueMember</ref>
321                         <ref type="application">UnpauseQueueMember</ref>
322                         <ref type="function">QUEUE_VARIABLES</ref>
323                         <ref type="function">QUEUE_MEMBER</ref>
324                         <ref type="function">QUEUE_MEMBER_COUNT</ref>
325                         <ref type="function">QUEUE_EXISTS</ref>
326                         <ref type="function">QUEUE_WAITING_COUNT</ref>
327                         <ref type="function">QUEUE_MEMBER_LIST</ref>
328                         <ref type="function">QUEUE_MEMBER_PENALTY</ref>
329                 </see-also>
330         </application>
331         <application name="RemoveQueueMember" language="en_US">
332                 <synopsis>
333                         Dynamically removes queue members.
334                 </synopsis>
335                 <syntax>
336                         <parameter name="queuename" required="true" />
337                         <parameter name="interface" />
338                 </syntax>
339                 <description>
340                         <para>If the interface is <emphasis>NOT</emphasis> in the queue it will return an error.</para>
341                         <para>This application sets the following channel variable upon completion:</para>
342                         <variablelist>
343                                 <variable name="RQMSTATUS">
344                                         <value name="REMOVED" />
345                                         <value name="NOTINQUEUE" />
346                                         <value name="NOSUCHQUEUE" />
347                                         <value name="NOTDYNAMIC" />
348                                 </variable>
349                         </variablelist>
350                         <para>Example: RemoveQueueMember(techsupport,SIP/3000)</para>
351                 </description>
352                 <see-also>
353                         <ref type="application">Queue</ref>
354                         <ref type="application">QueueLog</ref>
355                         <ref type="application">AddQueueMember</ref>
356                         <ref type="application">RemoveQueueMember</ref>
357                         <ref type="application">PauseQueueMember</ref>
358                         <ref type="application">UnpauseQueueMember</ref>
359                         <ref type="function">QUEUE_VARIABLES</ref>
360                         <ref type="function">QUEUE_MEMBER</ref>
361                         <ref type="function">QUEUE_MEMBER_COUNT</ref>
362                         <ref type="function">QUEUE_EXISTS</ref>
363                         <ref type="function">QUEUE_WAITING_COUNT</ref>
364                         <ref type="function">QUEUE_MEMBER_LIST</ref>
365                         <ref type="function">QUEUE_MEMBER_PENALTY</ref>
366                 </see-also>
367         </application>
368         <application name="PauseQueueMember" language="en_US">
369                 <synopsis>
370                         Pauses a queue member.
371                 </synopsis>
372                 <syntax>
373                         <parameter name="queuename" />
374                         <parameter name="interface" required="true" />
375                         <parameter name="options" />
376                         <parameter name="reason">
377                                 <para>Is used to add extra information to the appropriate queue_log entries and manager events.</para>
378                         </parameter>
379                 </syntax>
380                 <description>
381                         <para>Pauses (blocks calls for) a queue member. The given interface will be paused in the given queue.
382                         This prevents any calls from being sent from the queue to the interface until it is
383                         unpaused with UnpauseQueueMember or the manager interface.  If no queuename is given,
384                         the interface is paused in every queue it is a member of. The application will fail if the
385                         interface is not found.</para>
386                         <para>This application sets the following channel variable upon completion:</para>
387                         <variablelist>
388                                 <variable name="PQMSTATUS">
389                                         <para>The status of the attempt to pause a queue member as a text string.</para>
390                                         <value name="PAUSED" />
391                                         <value name="NOTFOUND" />
392                                 </variable>
393                         </variablelist>
394                         <para>Example: PauseQueueMember(,SIP/3000)</para>
395                 </description>
396                 <see-also>
397                         <ref type="application">Queue</ref>
398                         <ref type="application">QueueLog</ref>
399                         <ref type="application">AddQueueMember</ref>
400                         <ref type="application">RemoveQueueMember</ref>
401                         <ref type="application">PauseQueueMember</ref>
402                         <ref type="application">UnpauseQueueMember</ref>
403                         <ref type="function">QUEUE_VARIABLES</ref>
404                         <ref type="function">QUEUE_MEMBER</ref>
405                         <ref type="function">QUEUE_MEMBER_COUNT</ref>
406                         <ref type="function">QUEUE_EXISTS</ref>
407                         <ref type="function">QUEUE_WAITING_COUNT</ref>
408                         <ref type="function">QUEUE_MEMBER_LIST</ref>
409                         <ref type="function">QUEUE_MEMBER_PENALTY</ref>
410                 </see-also>
411         </application>
412         <application name="UnpauseQueueMember" language="en_US">
413                 <synopsis>
414                         Unpauses a queue member.
415                 </synopsis>
416                 <syntax>
417                         <parameter name="queuename" />
418                         <parameter name="interface" required="true" />
419                         <parameter name="options" />
420                         <parameter name="reason">
421                                 <para>Is used to add extra information to the appropriate queue_log entries and manager events.</para>
422                         </parameter>
423                 </syntax>
424                 <description>
425                         <para>Unpauses (resumes calls to) a queue member. This is the counterpart to <literal>PauseQueueMember()</literal>
426                         and operates exactly the same way, except it unpauses instead of pausing the given interface.</para>
427                         <para>This application sets the following channel variable upon completion:</para>
428                         <variablelist>
429                                 <variable name="UPQMSTATUS">
430                                         <para>The status of the attempt to unpause a queue member as a text string.</para>
431                                         <value name="UNPAUSED" />
432                                         <value name="NOTFOUND" />
433                                 </variable>
434                         </variablelist>
435                         <para>Example: UnpauseQueueMember(,SIP/3000)</para>
436                 </description>
437                 <see-also>
438                         <ref type="application">Queue</ref>
439                         <ref type="application">QueueLog</ref>
440                         <ref type="application">AddQueueMember</ref>
441                         <ref type="application">RemoveQueueMember</ref>
442                         <ref type="application">PauseQueueMember</ref>
443                         <ref type="application">UnpauseQueueMember</ref>
444                         <ref type="function">QUEUE_VARIABLES</ref>
445                         <ref type="function">QUEUE_MEMBER</ref>
446                         <ref type="function">QUEUE_MEMBER_COUNT</ref>
447                         <ref type="function">QUEUE_EXISTS</ref>
448                         <ref type="function">QUEUE_WAITING_COUNT</ref>
449                         <ref type="function">QUEUE_MEMBER_LIST</ref>
450                         <ref type="function">QUEUE_MEMBER_PENALTY</ref>
451                 </see-also>
452         </application>
453         <application name="QueueLog" language="en_US">
454                 <synopsis>
455                         Writes to the queue_log file.
456                 </synopsis>
457                 <syntax>
458                         <parameter name="queuename" required="true" />
459                         <parameter name="uniqueid" required="true" />
460                         <parameter name="agent" required="true" />
461                         <parameter name="event" required="true" />
462                         <parameter name="additionalinfo" />
463                 </syntax>
464                 <description>
465                         <para>Allows you to write your own events into the queue log.</para>
466                         <para>Example: QueueLog(101,${UNIQUEID},${AGENT},WENTONBREAK,600)</para>
467                 </description>
468                 <see-also>
469                         <ref type="application">Queue</ref>
470                         <ref type="application">QueueLog</ref>
471                         <ref type="application">AddQueueMember</ref>
472                         <ref type="application">RemoveQueueMember</ref>
473                         <ref type="application">PauseQueueMember</ref>
474                         <ref type="application">UnpauseQueueMember</ref>
475                         <ref type="function">QUEUE_VARIABLES</ref>
476                         <ref type="function">QUEUE_MEMBER</ref>
477                         <ref type="function">QUEUE_MEMBER_COUNT</ref>
478                         <ref type="function">QUEUE_EXISTS</ref>
479                         <ref type="function">QUEUE_WAITING_COUNT</ref>
480                         <ref type="function">QUEUE_MEMBER_LIST</ref>
481                         <ref type="function">QUEUE_MEMBER_PENALTY</ref>
482                 </see-also>
483         </application>
484         <function name="QUEUE_VARIABLES" language="en_US">
485                 <synopsis>
486                         Return Queue information in variables.
487                 </synopsis>
488                 <syntax>
489                         <parameter name="queuename" required="true">
490                                 <enumlist>
491                                         <enum name="QUEUEMAX">
492                                                 <para>Maxmimum number of calls allowed.</para>
493                                         </enum>
494                                         <enum name="QUEUESTRATEGY">
495                                                 <para>The strategy of the queue.</para>
496                                         </enum>
497                                         <enum name="QUEUECALLS">
498                                                 <para>Number of calls currently in the queue.</para>
499                                         </enum>
500                                         <enum name="QUEUEHOLDTIME">
501                                                 <para>Current average hold time.</para>
502                                         </enum>
503                                         <enum name="QUEUECOMPLETED">
504                                                 <para>Number of completed calls for the queue.</para>
505                                         </enum>
506                                         <enum name="QUEUEABANDONED">
507                                                 <para>Number of abandoned calls.</para>
508                                         </enum>
509                                         <enum name="QUEUESRVLEVEL">
510                                                 <para>Queue service level.</para>
511                                         </enum>
512                                         <enum name="QUEUESRVLEVELPERF">
513                                                 <para>Current service level performance.</para>
514                                         </enum>
515                                 </enumlist>
516                         </parameter>
517                 </syntax>
518                 <description>
519                         <para>Makes the following queue variables available.</para>
520                         <para>Returns <literal>0</literal> if queue is found and setqueuevar is defined, <literal>-1</literal> otherwise.</para>
521                 </description>
522                 <see-also>
523                         <ref type="application">Queue</ref>
524                         <ref type="application">QueueLog</ref>
525                         <ref type="application">AddQueueMember</ref>
526                         <ref type="application">RemoveQueueMember</ref>
527                         <ref type="application">PauseQueueMember</ref>
528                         <ref type="application">UnpauseQueueMember</ref>
529                         <ref type="function">QUEUE_VARIABLES</ref>
530                         <ref type="function">QUEUE_MEMBER</ref>
531                         <ref type="function">QUEUE_MEMBER_COUNT</ref>
532                         <ref type="function">QUEUE_EXISTS</ref>
533                         <ref type="function">QUEUE_WAITING_COUNT</ref>
534                         <ref type="function">QUEUE_MEMBER_LIST</ref>
535                         <ref type="function">QUEUE_MEMBER_PENALTY</ref>
536                 </see-also>
537         </function>
538         <function name="QUEUE_MEMBER" language="en_US">
539                 <synopsis>
540                         Count number of members answering a queue.
541                 </synopsis>
542                 <syntax>
543                         <parameter name="queuename" required="true" />
544                         <parameter name="option" required="true">
545                                 <enumlist>
546                                         <enum name="logged">
547                                                 <para>Returns the number of logged-in members for the specified queue.</para>
548                                         </enum>
549                                         <enum name="free">
550                                                 <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>
551                                         </enum>
552                                         <enum name="ready">
553                                                 <para>Returns the number of logged-in members for the specified queue that are immediately available to answer a call.</para>
554                                         </enum>
555                                         <enum name="count">
556                                                 <para>Returns the total number of members for the specified queue.</para>
557                                         </enum>
558                                         <enum name="penalty">
559                                                 <para>Gets or sets queue member penalty.</para>
560                                         </enum>
561                                         <enum name="paused">
562                                                 <para>Gets or sets queue member paused status.</para>
563                                         </enum>
564                                         <enum name="ringinuse">
565                                                 <para>Gets or sets queue member ringinuse.</para>
566                                         </enum>
567                                 </enumlist>
568                         </parameter>
569                         <parameter name="interface" required="false" />
570                 </syntax>
571                 <description>
572                         <para>Allows access to queue counts [R] and member information [R/W].</para>
573                         <para>
574                                 <replaceable>queuename</replaceable> is required for all operations
575                                 <replaceable>interface</replaceable> is required for all member operations.
576                         </para>
577                 </description>
578                 <see-also>
579                         <ref type="application">Queue</ref>
580                         <ref type="application">QueueLog</ref>
581                         <ref type="application">AddQueueMember</ref>
582                         <ref type="application">RemoveQueueMember</ref>
583                         <ref type="application">PauseQueueMember</ref>
584                         <ref type="application">UnpauseQueueMember</ref>
585                         <ref type="function">QUEUE_VARIABLES</ref>
586                         <ref type="function">QUEUE_MEMBER</ref>
587                         <ref type="function">QUEUE_MEMBER_COUNT</ref>
588                         <ref type="function">QUEUE_EXISTS</ref>
589                         <ref type="function">QUEUE_WAITING_COUNT</ref>
590                         <ref type="function">QUEUE_MEMBER_LIST</ref>
591                         <ref type="function">QUEUE_MEMBER_PENALTY</ref>
592                 </see-also>
593         </function>
594         <function name="QUEUE_MEMBER_COUNT" language="en_US">
595                 <synopsis>
596                         Count number of members answering a queue.
597                 </synopsis>
598                 <syntax>
599                         <parameter name="queuename" required="true" />
600                 </syntax>
601                 <description>
602                         <para>Returns the number of members currently associated with the specified <replaceable>queuename</replaceable>.</para>
603                         <warning><para>This function has been deprecated in favor of the <literal>QUEUE_MEMBER()</literal> function</para></warning>
604                 </description>
605                 <see-also>
606                         <ref type="application">Queue</ref>
607                         <ref type="application">QueueLog</ref>
608                         <ref type="application">AddQueueMember</ref>
609                         <ref type="application">RemoveQueueMember</ref>
610                         <ref type="application">PauseQueueMember</ref>
611                         <ref type="application">UnpauseQueueMember</ref>
612                         <ref type="function">QUEUE_VARIABLES</ref>
613                         <ref type="function">QUEUE_MEMBER</ref>
614                         <ref type="function">QUEUE_MEMBER_COUNT</ref>
615                         <ref type="function">QUEUE_EXISTS</ref>
616                         <ref type="function">QUEUE_WAITING_COUNT</ref>
617                         <ref type="function">QUEUE_MEMBER_LIST</ref>
618                         <ref type="function">QUEUE_MEMBER_PENALTY</ref>
619                 </see-also>
620         </function>
621         <function name="QUEUE_EXISTS" language="en_US">
622                 <synopsis>
623                         Check if a named queue exists on this server
624                 </synopsis>
625                 <syntax>
626                         <parameter name="queuename" />
627                 </syntax>
628                 <description>
629                         <para>Returns 1 if the specified queue exists, 0 if it does not</para>
630                 </description>
631                 <see-also>
632                         <ref type="application">Queue</ref>
633                         <ref type="application">QueueLog</ref>
634                         <ref type="application">AddQueueMember</ref>
635                         <ref type="application">RemoveQueueMember</ref>
636                         <ref type="application">PauseQueueMember</ref>
637                         <ref type="application">UnpauseQueueMember</ref>
638                         <ref type="function">QUEUE_VARIABLES</ref>
639                         <ref type="function">QUEUE_MEMBER</ref>
640                         <ref type="function">QUEUE_MEMBER_COUNT</ref>
641                         <ref type="function">QUEUE_EXISTS</ref>
642                         <ref type="function">QUEUE_WAITING_COUNT</ref>
643                         <ref type="function">QUEUE_MEMBER_LIST</ref>
644                         <ref type="function">QUEUE_MEMBER_PENALTY</ref>
645                 </see-also>
646         </function>
647         <function name="QUEUE_WAITING_COUNT" language="en_US">
648                 <synopsis>
649                         Count number of calls currently waiting in a queue.
650                 </synopsis>
651                 <syntax>
652                         <parameter name="queuename" />
653                 </syntax>
654                 <description>
655                         <para>Returns the number of callers currently waiting in the specified <replaceable>queuename</replaceable>.</para>
656                 </description>
657                 <see-also>
658                         <ref type="application">Queue</ref>
659                         <ref type="application">QueueLog</ref>
660                         <ref type="application">AddQueueMember</ref>
661                         <ref type="application">RemoveQueueMember</ref>
662                         <ref type="application">PauseQueueMember</ref>
663                         <ref type="application">UnpauseQueueMember</ref>
664                         <ref type="function">QUEUE_VARIABLES</ref>
665                         <ref type="function">QUEUE_MEMBER</ref>
666                         <ref type="function">QUEUE_MEMBER_COUNT</ref>
667                         <ref type="function">QUEUE_EXISTS</ref>
668                         <ref type="function">QUEUE_WAITING_COUNT</ref>
669                         <ref type="function">QUEUE_MEMBER_LIST</ref>
670                         <ref type="function">QUEUE_MEMBER_PENALTY</ref>
671                 </see-also>
672         </function>
673         <function name="QUEUE_MEMBER_LIST" language="en_US">
674                 <synopsis>
675                         Returns a list of interfaces on a queue.
676                 </synopsis>
677                 <syntax>
678                         <parameter name="queuename" required="true" />
679                 </syntax>
680                 <description>
681                         <para>Returns a comma-separated list of members associated with the specified <replaceable>queuename</replaceable>.</para>
682                 </description>
683                 <see-also>
684                         <ref type="application">Queue</ref>
685                         <ref type="application">QueueLog</ref>
686                         <ref type="application">AddQueueMember</ref>
687                         <ref type="application">RemoveQueueMember</ref>
688                         <ref type="application">PauseQueueMember</ref>
689                         <ref type="application">UnpauseQueueMember</ref>
690                         <ref type="function">QUEUE_VARIABLES</ref>
691                         <ref type="function">QUEUE_MEMBER</ref>
692                         <ref type="function">QUEUE_MEMBER_COUNT</ref>
693                         <ref type="function">QUEUE_EXISTS</ref>
694                         <ref type="function">QUEUE_WAITING_COUNT</ref>
695                         <ref type="function">QUEUE_MEMBER_LIST</ref>
696                         <ref type="function">QUEUE_MEMBER_PENALTY</ref>
697                 </see-also>
698         </function>
699         <function name="QUEUE_MEMBER_PENALTY" language="en_US">
700                 <synopsis>
701                         Gets or sets queue members penalty.
702                 </synopsis>
703                 <syntax>
704                         <parameter name="queuename" required="true" />
705                         <parameter name="interface" required="true" />
706                 </syntax>
707                 <description>
708                         <para>Gets or sets queue members penalty.</para>
709                         <warning><para>This function has been deprecated in favor of the <literal>QUEUE_MEMBER()</literal> function</para></warning>
710                 </description>
711                 <see-also>
712                         <ref type="application">Queue</ref>
713                         <ref type="application">QueueLog</ref>
714                         <ref type="application">AddQueueMember</ref>
715                         <ref type="application">RemoveQueueMember</ref>
716                         <ref type="application">PauseQueueMember</ref>
717                         <ref type="application">UnpauseQueueMember</ref>
718                         <ref type="function">QUEUE_VARIABLES</ref>
719                         <ref type="function">QUEUE_MEMBER</ref>
720                         <ref type="function">QUEUE_MEMBER_COUNT</ref>
721                         <ref type="function">QUEUE_EXISTS</ref>
722                         <ref type="function">QUEUE_WAITING_COUNT</ref>
723                         <ref type="function">QUEUE_MEMBER_LIST</ref>
724                         <ref type="function">QUEUE_MEMBER_PENALTY</ref>
725                 </see-also>
726         </function>
727         <manager name="Queues" language="en_US">
728                 <synopsis>
729                         Queues.
730                 </synopsis>
731                 <syntax>
732                 </syntax>
733                 <description>
734                 </description>
735         </manager>
736         <manager name="QueueStatus" language="en_US">
737                 <synopsis>
738                         Show queue status.
739                 </synopsis>
740                 <syntax>
741                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
742                         <parameter name="Queue" />
743                         <parameter name="Member" />
744                 </syntax>
745                 <description>
746                 </description>
747         </manager>
748         <manager name="QueueSummary" language="en_US">
749                 <synopsis>
750                         Show queue summary.
751                 </synopsis>
752                 <syntax>
753                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
754                         <parameter name="Queue" />
755                 </syntax>
756                 <description>
757                 </description>
758         </manager>
759         <manager name="QueueAdd" language="en_US">
760                 <synopsis>
761                         Add interface to queue.
762                 </synopsis>
763                 <syntax>
764                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
765                         <parameter name="Queue" required="true" />
766                         <parameter name="Interface" required="true" />
767                         <parameter name="Penalty" />
768                         <parameter name="Paused" />
769                         <parameter name="MemberName" />
770                         <parameter name="StateInterface" />
771                 </syntax>
772                 <description>
773                 </description>
774         </manager>
775         <manager name="QueueRemove" language="en_US">
776                 <synopsis>
777                         Remove interface from queue.
778                 </synopsis>
779                 <syntax>
780                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
781                         <parameter name="Queue" required="true" />
782                         <parameter name="Interface" required="true" />
783                 </syntax>
784                 <description>
785                 </description>
786         </manager>
787         <manager name="QueuePause" language="en_US">
788                 <synopsis>
789                         Makes a queue member temporarily unavailable.
790                 </synopsis>
791                 <syntax>
792                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
793                         <parameter name="Interface" required="true" />
794                         <parameter name="Paused" required="true" />
795                         <parameter name="Queue" />
796                         <parameter name="Reason" />
797                 </syntax>
798                 <description>
799                 </description>
800         </manager>
801         <manager name="QueueLog" language="en_US">
802                 <synopsis>
803                         Adds custom entry in queue_log.
804                 </synopsis>
805                 <syntax>
806                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
807                         <parameter name="Queue" required="true" />
808                         <parameter name="Event" required="true" />
809                         <parameter name="Uniqueid" />
810                         <parameter name="Interface" />
811                         <parameter name="Message" />
812                 </syntax>
813                 <description>
814                 </description>
815         </manager>
816         <manager name="QueuePenalty" language="en_US">
817                 <synopsis>
818                         Set the penalty for a queue member.
819                 </synopsis>
820                 <syntax>
821                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
822                         <parameter name="Interface" required="true" />
823                         <parameter name="Penalty" required="true" />
824                         <parameter name="Queue" />
825                 </syntax>
826                 <description>
827                 </description>
828         </manager>
829         <manager name="QueueMemberRingInUse" language="en_US">
830                 <synopsis>
831                         Set the ringinuse value for a queue member.
832                 </synopsis>
833                 <syntax>
834                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
835                         <parameter name="Interface" required="true" />
836                         <parameter name="RingInUse" required="true" />
837                         <parameter name="Queue" />
838                 </syntax>
839                 <description>
840                 </description>
841         </manager>
842         <manager name="QueueRule" language="en_US">
843                 <synopsis>
844                         Queue Rules.
845                 </synopsis>
846                 <syntax>
847                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
848                         <parameter name="Rule" />
849                 </syntax>
850                 <description>
851                 </description>
852         </manager>
853         <manager name="QueueReload" language="en_US">
854                 <synopsis>
855                         Reload a queue, queues, or any sub-section of a queue or queues.
856                 </synopsis>
857                 <syntax>
858                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
859                         <parameter name="Queue" />
860                         <parameter name="Members">
861                                 <enumlist>
862                                         <enum name="yes" />
863                                         <enum name="no" />
864                                 </enumlist>
865                         </parameter>
866                         <parameter name="Rules">
867                                 <enumlist>
868                                         <enum name="yes" />
869                                         <enum name="no" />
870                                 </enumlist>
871                         </parameter>
872                         <parameter name="Parameters">
873                                 <enumlist>
874                                         <enum name="yes" />
875                                         <enum name="no" />
876                                 </enumlist>
877                         </parameter>
878                 </syntax>
879                 <description>
880                 </description>
881         </manager>
882         <manager name="QueueReset" language="en_US">
883                 <synopsis>
884                         Reset queue statistics.
885                 </synopsis>
886                 <syntax>
887                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
888                         <parameter name="Queue" />
889                 </syntax>
890                 <description>
891                 </description>
892         </manager>
893
894         <managerEvent language="en_US" name="QueueMemberStatus">
895                 <managerEventInstance class="EVENT_FLAG_AGENT">
896                         <synopsis>Raised when a Queue member's status has changed.</synopsis>
897                         <syntax>
898                                 <parameter name="Queue">
899                                         <para>The name of the queue.</para>
900                                 </parameter>
901                                 <parameter name="MemberName">
902                                         <para>The name of the queue member.</para>
903                                 </parameter>
904                                 <parameter name="Interface">
905                                         <para>The queue member's channel technology or location.</para>
906                                 </parameter>
907                                 <parameter name="StateInterface">
908                                         <para>Channel technology or location from which to read device state changes.</para>
909                                 </parameter>
910                                 <parameter name="Membership">
911                                         <enumlist>
912                                                 <enum name="dynamic"/>
913                                                 <enum name="realtime"/>
914                                                 <enum name="static"/>
915                                         </enumlist>
916                                 </parameter>
917                                 <parameter name="Penalty">
918                                         <para>The penalty associated with the queue member.</para>
919                                 </parameter>
920                                 <parameter name="CallsTaken">
921                                         <para>The number of calls this queue member has serviced.</para>
922                                 </parameter>
923                                 <parameter name="LastCall">
924                                         <para>The time this member last took a call, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
925                                 </parameter>
926                                 <parameter name="Status">
927                                         <para>The numeric device state status of the queue member.</para>
928                                         <enumlist>
929                                                 <enum name="0"><para>AST_DEVICE_UNKNOWN</para></enum>
930                                                 <enum name="1"><para>AST_DEVICE_NOT_INUSE</para></enum>
931                                                 <enum name="2"><para>AST_DEVICE_INUSE</para></enum>
932                                                 <enum name="3"><para>AST_DEVICE_BUSY</para></enum>
933                                                 <enum name="4"><para>AST_DEVICE_INVALID</para></enum>
934                                                 <enum name="5"><para>AST_DEVICE_UNAVAILABLE</para></enum>
935                                                 <enum name="6"><para>AST_DEVICE_RINGING</para></enum>
936                                                 <enum name="7"><para>AST_DEVICE_RINGINUSE</para></enum>
937                                                 <enum name="8"><para>AST_DEVICE_ONHOLD</para></enum>
938                                         </enumlist>
939                                 </parameter>
940                                 <parameter name="Paused">
941                                         <enumlist>
942                                                 <enum name="0"/>
943                                                 <enum name="1"/>
944                                         </enumlist>
945                                 </parameter>
946                                 <parameter name="Ringinuse">
947                                         <enumlist>
948                                                 <enum name="0"/>
949                                                 <enum name="1"/>
950                                         </enumlist>
951                                 </parameter>
952                         </syntax>
953                 </managerEventInstance>
954         </managerEvent>
955         <managerEvent language="en_US" name="QueueMemberAdded">
956                 <managerEventInstance class="EVENT_FLAG_AGENT">
957                         <synopsis>Raised when a member is added to the queue.</synopsis>
958                         <syntax>
959                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
960                         </syntax>
961                         <see-also>
962                                 <ref type="managerEvent">QueueMemberRemoved</ref>
963                                 <ref type="application">AddQueueMember</ref>
964                         </see-also>
965                 </managerEventInstance>
966         </managerEvent>
967         <managerEvent language="en_US" name="QueueMemberRemoved">
968                 <managerEventInstance class="EVENT_FLAG_AGENT">
969                         <synopsis>Raised when a member is removed from the queue.</synopsis>
970                         <syntax>
971                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
972                         </syntax>
973                         <see-also>
974                                 <ref type="managerEvent">QueueMemberAdded</ref>
975                                 <ref type="application">RemoveQueueMember</ref>
976                         </see-also>
977                 </managerEventInstance>
978         </managerEvent>
979         <managerEvent language="en_US" name="QueueMemberPaused">
980                 <managerEventInstance class="EVENT_FLAG_AGENT">
981                         <synopsis>Raised when a member is paused/unpaused in the queue.</synopsis>
982                         <syntax>
983                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
984                                 <parameter name="Reason">
985                                         <para>The reason a member was paused.</para>
986                                 </parameter>
987                         </syntax>
988                         <see-also>
989                                 <ref type="application">PauseQueueMember</ref>
990                                 <ref type="application">UnPauseQueueMember</ref>
991                         </see-also>
992                 </managerEventInstance>
993         </managerEvent>
994         <managerEvent language="en_US" name="QueueMemberPenalty">
995                 <managerEventInstance class="EVENT_FLAG_AGENT">
996                         <synopsis>Raised when a member's penalty is changed.</synopsis>
997                         <syntax>
998                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
999                         </syntax>
1000                         <see-also>
1001                                 <ref type="function">QUEUE_MEMBER</ref>
1002                         </see-also>
1003                 </managerEventInstance>
1004         </managerEvent>
1005         <managerEvent language="en_US" name="QueueMemberRinginuse">
1006                 <managerEventInstance class="EVENT_FLAG_AGENT">
1007                         <synopsis>Raised when a member's ringinuse setting is changed.</synopsis>
1008                         <syntax>
1009                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
1010                         </syntax>
1011                         <see-also>
1012                                 <ref type="function">QUEUE_MEMBER</ref>
1013                         </see-also>
1014                 </managerEventInstance>
1015         </managerEvent>
1016         <managerEvent language="en_US" name="QueueCallerJoin">
1017                 <managerEventInstance class="EVENT_FLAG_AGENT">
1018                         <synopsis>Raised when a caller joins a Queue.</synopsis>
1019                         <syntax>
1020                                 <channel_snapshot/>
1021                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1022                                 <parameter name="Position">
1023                                         <para>This channel's current position in the queue.</para>
1024                                 </parameter>
1025                                 <parameter name="Count">
1026                                         <para>The total number of channels in the queue.</para>
1027                                 </parameter>
1028                         </syntax>
1029                         <see-also>
1030                                 <ref type="managerEvent">QueueCallerLeave</ref>
1031                                 <ref type="application">Queue</ref>
1032                         </see-also>
1033                 </managerEventInstance>
1034         </managerEvent>
1035         <managerEvent language="en_US" name="QueueCallerLeave">
1036                 <managerEventInstance class="EVENT_FLAG_AGENT">
1037                         <synopsis>Raised when a caller leaves a Queue.</synopsis>
1038                         <syntax>
1039                                 <channel_snapshot/>
1040                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1041                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerJoin']/managerEventInstance/syntax/parameter[@name='Count'])" />
1042                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerJoin']/managerEventInstance/syntax/parameter[@name='Position'])" />
1043                         </syntax>
1044                         <see-also>
1045                                 <ref type="managerEvent">QueueCallerJoin</ref>
1046                         </see-also>
1047                 </managerEventInstance>
1048         </managerEvent>
1049         <managerEvent language="en_US" name="QueueCallerAbandon">
1050                 <managerEventInstance class="EVENT_FLAG_AGENT">
1051                         <synopsis>Raised when a caller abandons the queue.</synopsis>
1052                         <syntax>
1053                                 <channel_snapshot/>
1054                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1055                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerJoin']/managerEventInstance/syntax/parameter[@name='Position'])" />
1056                                 <parameter name="OriginalPosition">
1057                                         <para>The channel's original position in the queue.</para>
1058                                 </parameter>
1059                                 <parameter name="HoldTime">
1060                                         <para>The time the channel was in the queue, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
1061                                 </parameter>
1062                         </syntax>
1063                 </managerEventInstance>
1064         </managerEvent>
1065         <managerEvent language="en_US" name="AgentCalled">
1066                 <managerEventInstance class="EVENT_FLAG_AGENT">
1067                         <synopsis>Raised when an queue member is notified of a caller in the queue.</synopsis>
1068                         <syntax>
1069                                 <channel_snapshot/>
1070                                 <channel_snapshot prefix="Dest"/>
1071                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1072                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
1073                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
1074                         </syntax>
1075                         <see-also>
1076                                 <ref type="managerEvent">AgentRingNoAnswer</ref>
1077                                 <ref type="managerEvent">AgentComplete</ref>
1078                                 <ref type="managerEvent">AgentConnect</ref>
1079                         </see-also>
1080                 </managerEventInstance>
1081         </managerEvent>
1082         <managerEvent language="en_US" name="AgentRingNoAnswer">
1083                 <managerEventInstance class="EVENT_FLAG_AGENT">
1084                         <synopsis>Raised when a queue member is notified of a caller in the queue and fails to answer.</synopsis>
1085                         <syntax>
1086                                 <channel_snapshot/>
1087                                 <channel_snapshot prefix="Dest"/>
1088                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1089                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
1090                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
1091                                 <parameter name="RingTime">
1092                                         <para>The time the queue member was rung, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
1093                                 </parameter>
1094                         </syntax>
1095                         <see-also>
1096                                 <ref type="managerEvent">AgentCalled</ref>
1097                         </see-also>
1098                 </managerEventInstance>
1099         </managerEvent>
1100         <managerEvent language="en_US" name="AgentComplete">
1101                 <managerEventInstance class="EVENT_FLAG_AGENT">
1102                         <synopsis>Raised when a queue member has finished servicing a caller in the queue.</synopsis>
1103                         <syntax>
1104                                 <channel_snapshot/>
1105                                 <channel_snapshot prefix="Dest"/>
1106                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1107                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
1108                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
1109                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerAbandon']/managerEventInstance/syntax/parameter[@name='HoldTime'])" />
1110                                 <parameter name="TalkTime">
1111                                         <para>The time the queue member talked with the caller in the queue, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
1112                                 </parameter>
1113                                 <parameter name="Reason">
1114                                         <enumlist>
1115                                                 <enum name="caller"/>
1116                                                 <enum name="agent"/>
1117                                                 <enum name="transfer"/>
1118                                         </enumlist>
1119                                 </parameter>
1120                         </syntax>
1121                         <see-also>
1122                                 <ref type="managerEvent">AgentCalled</ref>
1123                                 <ref type="managerEvent">AgentConnect</ref>
1124                         </see-also>
1125                 </managerEventInstance>
1126         </managerEvent>
1127         <managerEvent language="en_US" name="AgentDump">
1128                 <managerEventInstance class="EVENT_FLAG_AGENT">
1129                         <synopsis>Raised when a queue member hangs up on a caller in the queue.</synopsis>
1130                         <syntax>
1131                                 <channel_snapshot/>
1132                                 <channel_snapshot prefix="Dest"/>
1133                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1134                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
1135                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
1136                         </syntax>
1137                         <see-also>
1138                                 <ref type="managerEvent">AgentCalled</ref>
1139                                 <ref type="managerEvent">AgentConnect</ref>
1140                         </see-also>
1141                 </managerEventInstance>
1142         </managerEvent>
1143         <managerEvent language="en_US" name="AgentConnect">
1144                 <managerEventInstance class="EVENT_FLAG_AGENT">
1145                         <synopsis>Raised when a queue member answers and is bridged to a caller in the queue.</synopsis>
1146                         <syntax>
1147                                 <channel_snapshot/>
1148                                 <channel_snapshot prefix="Dest"/>
1149                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1150                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
1151                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
1152                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='AgentRingNoAnswer']/managerEventInstance/syntax/parameter[@name='RingTime'])" />
1153                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerAbandon']/managerEventInstance/syntax/parameter[@name='HoldTime'])" />
1154                         </syntax>
1155                         <see-also>
1156                                 <ref type="managerEvent">AgentCalled</ref>
1157                                 <ref type="managerEvent">AgentComplete</ref>
1158                                 <ref type="managerEvent">AgentDump</ref>
1159                         </see-also>
1160                 </managerEventInstance>
1161         </managerEvent>
1162  ***/
1163
1164 enum {
1165         OPT_MARK_AS_ANSWERED =       (1 << 0),
1166         OPT_GO_ON =                  (1 << 1),
1167         OPT_DATA_QUALITY =           (1 << 2),
1168         OPT_CALLEE_GO_ON =           (1 << 3),
1169         OPT_CALLEE_HANGUP =          (1 << 4),
1170         OPT_CALLER_HANGUP =          (1 << 5),
1171         OPT_IGNORE_CALL_FW =         (1 << 6),
1172         OPT_IGNORE_CONNECTEDLINE =   (1 << 7),
1173         OPT_CALLEE_PARK =            (1 << 8),
1174         OPT_CALLER_PARK =            (1 << 9),
1175         OPT_NO_RETRY =               (1 << 10),
1176         OPT_RINGING =                (1 << 11),
1177         OPT_RING_WHEN_RINGING =      (1 << 12),
1178         OPT_CALLEE_TRANSFER =        (1 << 13),
1179         OPT_CALLER_TRANSFER =        (1 << 14),
1180         OPT_CALLEE_AUTOMIXMON =      (1 << 15),
1181         OPT_CALLER_AUTOMIXMON =      (1 << 16),
1182         OPT_CALLEE_AUTOMON =         (1 << 17),
1183         OPT_CALLER_AUTOMON =         (1 << 18),
1184 };
1185
1186 enum {
1187         OPT_ARG_CALLEE_GO_ON = 0,
1188         /* note: this entry _MUST_ be the last one in the enum */
1189         OPT_ARG_ARRAY_SIZE
1190 };
1191
1192 AST_APP_OPTIONS(queue_exec_options, BEGIN_OPTIONS
1193         AST_APP_OPTION('C', OPT_MARK_AS_ANSWERED),
1194         AST_APP_OPTION('c', OPT_GO_ON),
1195         AST_APP_OPTION('d', OPT_DATA_QUALITY),
1196         AST_APP_OPTION_ARG('F', OPT_CALLEE_GO_ON, OPT_ARG_CALLEE_GO_ON),
1197         AST_APP_OPTION('h', OPT_CALLEE_HANGUP),
1198         AST_APP_OPTION('H', OPT_CALLER_HANGUP),
1199         AST_APP_OPTION('i', OPT_IGNORE_CALL_FW),
1200         AST_APP_OPTION('I', OPT_IGNORE_CONNECTEDLINE),
1201         AST_APP_OPTION('k', OPT_CALLEE_PARK),
1202         AST_APP_OPTION('K', OPT_CALLER_PARK),
1203         AST_APP_OPTION('n', OPT_NO_RETRY),
1204         AST_APP_OPTION('r', OPT_RINGING),
1205         AST_APP_OPTION('R', OPT_RING_WHEN_RINGING),
1206         AST_APP_OPTION('t', OPT_CALLEE_TRANSFER),
1207         AST_APP_OPTION('T', OPT_CALLER_TRANSFER),
1208         AST_APP_OPTION('x', OPT_CALLEE_AUTOMIXMON),
1209         AST_APP_OPTION('X', OPT_CALLER_AUTOMIXMON),
1210         AST_APP_OPTION('w', OPT_CALLEE_AUTOMON),
1211         AST_APP_OPTION('W', OPT_CALLER_AUTOMON),
1212 END_OPTIONS);
1213
1214 enum {
1215         QUEUE_STRATEGY_RINGALL = 0,
1216         QUEUE_STRATEGY_LEASTRECENT,
1217         QUEUE_STRATEGY_FEWESTCALLS,
1218         QUEUE_STRATEGY_RANDOM,
1219         QUEUE_STRATEGY_RRMEMORY,
1220         QUEUE_STRATEGY_LINEAR,
1221         QUEUE_STRATEGY_WRANDOM,
1222         QUEUE_STRATEGY_RRORDERED,
1223 };
1224
1225 enum {
1226      QUEUE_AUTOPAUSE_OFF = 0,
1227      QUEUE_AUTOPAUSE_ON,
1228      QUEUE_AUTOPAUSE_ALL
1229 };
1230
1231 enum queue_reload_mask {
1232         QUEUE_RELOAD_PARAMETERS = (1 << 0),
1233         QUEUE_RELOAD_MEMBER = (1 << 1),
1234         QUEUE_RELOAD_RULES = (1 << 2),
1235         QUEUE_RESET_STATS = (1 << 3),
1236 };
1237
1238 static const struct strategy {
1239         int strategy;
1240         const char *name;
1241 } strategies[] = {
1242         { QUEUE_STRATEGY_RINGALL, "ringall" },
1243         { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
1244         { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
1245         { QUEUE_STRATEGY_RANDOM, "random" },
1246         { QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
1247         { QUEUE_STRATEGY_RRMEMORY, "roundrobin" },
1248         { QUEUE_STRATEGY_LINEAR, "linear" },
1249         { QUEUE_STRATEGY_WRANDOM, "wrandom"},
1250         { QUEUE_STRATEGY_RRORDERED, "rrordered"},
1251 };
1252
1253 static const struct autopause {
1254         int autopause;
1255         const char *name;
1256 } autopausesmodes [] = {
1257         { QUEUE_AUTOPAUSE_OFF,"no" },
1258         { QUEUE_AUTOPAUSE_ON, "yes" },
1259         { QUEUE_AUTOPAUSE_ALL,"all" },
1260 };
1261
1262 #define DEFAULT_RETRY           5
1263 #define DEFAULT_TIMEOUT         15
1264 #define RECHECK                 1               /*!< Recheck every second to see we we're at the top yet */
1265 #define MAX_PERIODIC_ANNOUNCEMENTS 10           /*!< The maximum periodic announcements we can have */
1266 #define DEFAULT_MIN_ANNOUNCE_FREQUENCY 15       /*!< The minimum number of seconds between position announcements \
1267                                                      The default value of 15 provides backwards compatibility */
1268 #define MAX_QUEUE_BUCKETS 53
1269
1270 #define RES_OKAY        0               /*!< Action completed */
1271 #define RES_EXISTS      (-1)            /*!< Entry already exists */
1272 #define RES_OUTOFMEMORY (-2)            /*!< Out of memory */
1273 #define RES_NOSUCHQUEUE (-3)            /*!< No such queue */
1274 #define RES_NOT_DYNAMIC (-4)            /*!< Member is not dynamic */
1275
1276 static char *app = "Queue";
1277
1278 static char *app_aqm = "AddQueueMember" ;
1279
1280 static char *app_rqm = "RemoveQueueMember" ;
1281
1282 static char *app_pqm = "PauseQueueMember" ;
1283
1284 static char *app_upqm = "UnpauseQueueMember" ;
1285
1286 static char *app_ql = "QueueLog" ;
1287
1288 /*! \brief Persistent Members astdb family */
1289 static const char * const pm_family = "Queue/PersistentMembers";
1290
1291 /*! \brief queues.conf [general] option */
1292 static int queue_persistent_members = 0;
1293
1294 /*! \brief queues.conf per-queue weight option */
1295 static int use_weight = 0;
1296
1297 /*! \brief queues.conf [general] option */
1298 static int autofill_default = 1;
1299
1300 /*! \brief queues.conf [general] option */
1301 static int montype_default = 0;
1302
1303 /*! \brief queues.conf [general] option */
1304 static int shared_lastcall = 1;
1305
1306 /*! \brief Subscription to device state change messages */
1307 static struct stasis_subscription *device_state_sub;
1308
1309 /*! \brief queues.conf [general] option */
1310 static int update_cdr = 0;
1311
1312 /*! \brief queues.conf [general] option */
1313 static int negative_penalty_invalid = 0;
1314
1315 /*! \brief queues.conf [general] option */
1316 static int log_membername_as_agent = 0;
1317
1318 /*! \brief name of the ringinuse field in the realtime database */
1319 static char *realtime_ringinuse_field;
1320
1321 enum queue_result {
1322         QUEUE_UNKNOWN = 0,
1323         QUEUE_TIMEOUT = 1,
1324         QUEUE_JOINEMPTY = 2,
1325         QUEUE_LEAVEEMPTY = 3,
1326         QUEUE_JOINUNAVAIL = 4,
1327         QUEUE_LEAVEUNAVAIL = 5,
1328         QUEUE_FULL = 6,
1329         QUEUE_CONTINUE = 7,
1330 };
1331
1332 static const struct {
1333         enum queue_result id;
1334         char *text;
1335 } queue_results[] = {
1336         { QUEUE_UNKNOWN, "UNKNOWN" },
1337         { QUEUE_TIMEOUT, "TIMEOUT" },
1338         { QUEUE_JOINEMPTY,"JOINEMPTY" },
1339         { QUEUE_LEAVEEMPTY, "LEAVEEMPTY" },
1340         { QUEUE_JOINUNAVAIL, "JOINUNAVAIL" },
1341         { QUEUE_LEAVEUNAVAIL, "LEAVEUNAVAIL" },
1342         { QUEUE_FULL, "FULL" },
1343         { QUEUE_CONTINUE, "CONTINUE" },
1344 };
1345
1346 enum queue_timeout_priority {
1347         TIMEOUT_PRIORITY_APP,
1348         TIMEOUT_PRIORITY_CONF,
1349 };
1350
1351 /*! \brief We define a custom "local user" structure because we
1352  *  use it not only for keeping track of what is in use but
1353  *  also for keeping track of who we're dialing.
1354  *
1355  *  There are two "links" defined in this structure, q_next and call_next.
1356  *  q_next links ALL defined callattempt structures into a linked list. call_next is
1357  *  a link which allows for a subset of the callattempts to be traversed. This subset
1358  *  is used in wait_for_answer so that irrelevant callattempts are not traversed. This
1359  *  also is helpful so that queue logs are always accurate in the case where a call to
1360  *  a member times out, especially if using the ringall strategy.
1361 */
1362
1363 struct callattempt {
1364         struct callattempt *q_next;
1365         struct callattempt *call_next;
1366         struct ast_channel *chan;
1367         char interface[256];                    /*!< An Asterisk dial string (not a channel name) */
1368         int metric;
1369         time_t lastcall;
1370         struct call_queue *lastqueue;
1371         struct member *member;
1372         /*! Saved connected party info from an AST_CONTROL_CONNECTED_LINE. */
1373         struct ast_party_connected_line connected;
1374         /*! TRUE if an AST_CONTROL_CONNECTED_LINE update was saved to the connected element. */
1375         unsigned int pending_connected_update:1;
1376         /*! TRUE if the connected line update is blocked. */
1377         unsigned int block_connected_update:1;
1378         /*! TRUE if caller id is not available for connected line */
1379         unsigned int dial_callerid_absent:1;
1380         /*! TRUE if the call is still active */
1381         unsigned int stillgoing:1;
1382         struct ast_aoc_decoded *aoc_s_rate_list;
1383 };
1384
1385
1386 struct queue_ent {
1387         struct call_queue *parent;             /*!< What queue is our parent */
1388         char moh[MAX_MUSICCLASS];              /*!< Name of musiconhold to be used */
1389         char announce[PATH_MAX];               /*!< Announcement to play for member when call is answered */
1390         char context[AST_MAX_CONTEXT];         /*!< Context when user exits queue */
1391         char digits[AST_MAX_EXTENSION];        /*!< Digits entered while in queue */
1392         int valid_digits;                      /*!< Digits entered correspond to valid extension. Exited */
1393         int pos;                               /*!< Where we are in the queue */
1394         int prio;                              /*!< Our priority */
1395         int last_pos_said;                     /*!< Last position we told the user */
1396         int ring_when_ringing;                 /*!< Should we only use ring indication when a channel is ringing? */
1397         time_t last_periodic_announce_time;    /*!< The last time we played a periodic announcement */
1398         int last_periodic_announce_sound;      /*!< The last periodic announcement we made */
1399         time_t last_pos;                       /*!< Last time we told the user their position */
1400         int opos;                              /*!< Where we started in the queue */
1401         int handled;                           /*!< Whether our call was handled */
1402         int pending;                           /*!< Non-zero if we are attempting to call a member */
1403         int max_penalty;                       /*!< Limit the members that can take this call to this penalty or lower */
1404         int min_penalty;                       /*!< Limit the members that can take this call to this penalty or higher */
1405         int linpos;                            /*!< If using linear strategy, what position are we at? */
1406         int linwrapped;                        /*!< Is the linpos wrapped? */
1407         time_t start;                          /*!< When we started holding */
1408         time_t expire;                         /*!< When this entry should expire (time out of queue) */
1409         int cancel_answered_elsewhere;         /*!< Whether we should force the CAE flag on this call (C) option*/
1410         struct ast_channel *chan;              /*!< Our channel */
1411         AST_LIST_HEAD_NOLOCK(,penalty_rule) qe_rules; /*!< Local copy of the queue's penalty rules */
1412         struct penalty_rule *pr;               /*!< Pointer to the next penalty rule to implement */
1413         struct queue_ent *next;                /*!< The next queue entry */
1414 };
1415
1416 struct member {
1417         char interface[AST_CHANNEL_NAME];    /*!< Technology/Location to dial to reach this member*/
1418         char state_exten[AST_MAX_EXTENSION]; /*!< Extension to get state from (if using hint) */
1419         char state_context[AST_MAX_CONTEXT]; /*!< Context to use when getting state (if using hint) */
1420         char state_interface[AST_CHANNEL_NAME]; /*!< Technology/Location from which to read devicestate changes */
1421         char membername[80];                 /*!< Member name to use in queue logs */
1422         int penalty;                         /*!< Are we a last resort? */
1423         int calls;                           /*!< Number of calls serviced by this member */
1424         int dynamic;                         /*!< Are we dynamically added? */
1425         int realtime;                        /*!< Is this member realtime? */
1426         int status;                          /*!< Status of queue member */
1427         int paused;                          /*!< Are we paused (not accepting calls)? */
1428         int queuepos;                        /*!< In what order (pertains to certain strategies) should this member be called? */
1429         time_t lastcall;                     /*!< When last successful call was hungup */
1430         struct call_queue *lastqueue;        /*!< Last queue we received a call */
1431         unsigned int dead:1;                 /*!< Used to detect members deleted in realtime */
1432         unsigned int delme:1;                /*!< Flag to delete entry on reload */
1433         unsigned int call_pending:1;         /*!< TRUE if the Q is attempting to place a call to the member. */
1434         char rt_uniqueid[80];                /*!< Unique id of realtime member entry */
1435         unsigned int ringinuse:1;            /*!< Flag to ring queue members even if their status is 'inuse' */
1436 };
1437
1438 enum empty_conditions {
1439         QUEUE_EMPTY_PENALTY = (1 << 0),
1440         QUEUE_EMPTY_PAUSED = (1 << 1),
1441         QUEUE_EMPTY_INUSE = (1 << 2),
1442         QUEUE_EMPTY_RINGING = (1 << 3),
1443         QUEUE_EMPTY_UNAVAILABLE = (1 << 4),
1444         QUEUE_EMPTY_INVALID = (1 << 5),
1445         QUEUE_EMPTY_UNKNOWN = (1 << 6),
1446         QUEUE_EMPTY_WRAPUP = (1 << 7),
1447 };
1448
1449 enum member_properties {
1450         MEMBER_PENALTY = 0,
1451         MEMBER_RINGINUSE = 1,
1452 };
1453
1454 /* values used in multi-bit flags in call_queue */
1455 #define ANNOUNCEHOLDTIME_ALWAYS 1
1456 #define ANNOUNCEHOLDTIME_ONCE 2
1457 #define QUEUE_EVENT_VARIABLES 3
1458
1459 struct penalty_rule {
1460         int time;                           /*!< Number of seconds that need to pass before applying this rule */
1461         int max_value;                      /*!< The amount specified in the penalty rule for max penalty */
1462         int min_value;                      /*!< The amount specified in the penalty rule for min penalty */
1463         int max_relative;                   /*!< Is the max adjustment relative? 1 for relative, 0 for absolute */
1464         int min_relative;                   /*!< Is the min adjustment relative? 1 for relative, 0 for absolute */
1465         AST_LIST_ENTRY(penalty_rule) list;  /*!< Next penalty_rule */
1466 };
1467
1468 #define ANNOUNCEPOSITION_YES 1 /*!< We announce position */
1469 #define ANNOUNCEPOSITION_NO 2 /*!< We don't announce position */
1470 #define ANNOUNCEPOSITION_MORE_THAN 3 /*!< We say "Currently there are more than <limit>" */
1471 #define ANNOUNCEPOSITION_LIMIT 4 /*!< We not announce position more than <limit> */
1472
1473 struct call_queue {
1474         AST_DECLARE_STRING_FIELDS(
1475                 /*! Queue name */
1476                 AST_STRING_FIELD(name);
1477                 /*! Music on Hold class */
1478                 AST_STRING_FIELD(moh);
1479                 /*! Announcement to play when call is answered */
1480                 AST_STRING_FIELD(announce);
1481                 /*! Exit context */
1482                 AST_STRING_FIELD(context);
1483                 /*! Macro to run upon member connection */
1484                 AST_STRING_FIELD(membermacro);
1485                 /*! Gosub to run upon member connection */
1486                 AST_STRING_FIELD(membergosub);
1487                 /*! Default rule to use if none specified in call to Queue() */
1488                 AST_STRING_FIELD(defaultrule);
1489                 /*! Sound file: "Your call is now first in line" (def. queue-youarenext) */
1490                 AST_STRING_FIELD(sound_next);
1491                 /*! Sound file: "There are currently" (def. queue-thereare) */
1492                 AST_STRING_FIELD(sound_thereare);
1493                 /*! Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting) */
1494                 AST_STRING_FIELD(sound_calls);
1495                 /*! Sound file: "Currently there are more than" (def. queue-quantity1) */
1496                 AST_STRING_FIELD(queue_quantity1);
1497                 /*! Sound file: "callers waiting to speak with a representative" (def. queue-quantity2) */
1498                 AST_STRING_FIELD(queue_quantity2);
1499                 /*! Sound file: "The current estimated total holdtime is" (def. queue-holdtime) */
1500                 AST_STRING_FIELD(sound_holdtime);
1501                 /*! Sound file: "minutes." (def. queue-minutes) */
1502                 AST_STRING_FIELD(sound_minutes);
1503                 /*! Sound file: "minute." (def. queue-minute) */
1504                 AST_STRING_FIELD(sound_minute);
1505                 /*! Sound file: "seconds." (def. queue-seconds) */
1506                 AST_STRING_FIELD(sound_seconds);
1507                 /*! Sound file: "Thank you for your patience." (def. queue-thankyou) */
1508                 AST_STRING_FIELD(sound_thanks);
1509                 /*! Sound file: Custom announce for caller, no default */
1510                 AST_STRING_FIELD(sound_callerannounce);
1511                 /*! Sound file: "Hold time" (def. queue-reporthold) */
1512                 AST_STRING_FIELD(sound_reporthold);
1513         );
1514         /*! Sound files: Custom announce, no default */
1515         struct ast_str *sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS];
1516         unsigned int dead:1;
1517         unsigned int ringinuse:1;
1518         unsigned int announce_to_first_user:1; /*!< Whether or not we announce to the first user in a queue */
1519         unsigned int setinterfacevar:1;
1520         unsigned int setqueuevar:1;
1521         unsigned int setqueueentryvar:1;
1522         unsigned int reportholdtime:1;
1523         unsigned int wrapped:1;
1524         unsigned int timeoutrestart:1;
1525         unsigned int announceholdtime:2;
1526         unsigned int announceposition:3;
1527         int strategy:4;
1528         unsigned int realtime:1;
1529         unsigned int found:1;
1530         unsigned int relativeperiodicannounce:1;
1531         unsigned int autopausebusy:1;
1532         unsigned int autopauseunavail:1;
1533         enum empty_conditions joinempty;
1534         enum empty_conditions leavewhenempty;
1535         int announcepositionlimit;          /*!< How many positions we announce? */
1536         int announcefrequency;              /*!< How often to announce their position */
1537         int minannouncefrequency;           /*!< The minimum number of seconds between position announcements (def. 15) */
1538         int periodicannouncefrequency;      /*!< How often to play periodic announcement */
1539         int numperiodicannounce;            /*!< The number of periodic announcements configured */
1540         int randomperiodicannounce;         /*!< Are periodic announcments randomly chosen */
1541         int roundingseconds;                /*!< How many seconds do we round to? */
1542         int holdtime;                       /*!< Current avg holdtime, based on an exponential average */
1543         int talktime;                       /*!< Current avg talktime, based on the same exponential average */
1544         int callscompleted;                 /*!< Number of queue calls completed */
1545         int callsabandoned;                 /*!< Number of queue calls abandoned */
1546         int servicelevel;                   /*!< seconds setting for servicelevel*/
1547         int callscompletedinsl;             /*!< Number of calls answered with servicelevel*/
1548         char monfmt[8];                     /*!< Format to use when recording calls */
1549         int montype;                        /*!< Monitor type  Monitor vs. MixMonitor */
1550         int count;                          /*!< How many entries */
1551         int maxlen;                         /*!< Max number of entries */
1552         int wrapuptime;                     /*!< Wrapup Time */
1553         int penaltymemberslimit;            /*!< Disregard penalty when queue has fewer than this many members */
1554
1555         int retry;                          /*!< Retry calling everyone after this amount of time */
1556         int timeout;                        /*!< How long to wait for an answer */
1557         int weight;                         /*!< Respective weight */
1558         int autopause;                      /*!< Auto pause queue members if they fail to answer */
1559         int autopausedelay;                 /*!< Delay auto pause for autopausedelay seconds since last call */
1560         int timeoutpriority;                /*!< Do we allow a fraction of the timeout to occur for a ring? */
1561
1562         /* Queue strategy things */
1563         int rrpos;                          /*!< Round Robin - position */
1564         int memberdelay;                    /*!< Seconds to delay connecting member to caller */
1565         int autofill;                       /*!< Ignore the head call status and ring an available agent */
1566
1567         struct ao2_container *members;             /*!< Head of the list of members */
1568         struct queue_ent *head;             /*!< Head of the list of callers */
1569         AST_LIST_ENTRY(call_queue) list;    /*!< Next call queue */
1570         AST_LIST_HEAD_NOLOCK(, penalty_rule) rules; /*!< The list of penalty rules to invoke */
1571 };
1572
1573 struct rule_list {
1574         char name[80];
1575         AST_LIST_HEAD_NOLOCK(,penalty_rule) rules;
1576         AST_LIST_ENTRY(rule_list) list;
1577 };
1578
1579 static AST_LIST_HEAD_STATIC(rule_lists, rule_list);
1580
1581 static struct ao2_container *queues;
1582
1583 static void update_realtime_members(struct call_queue *q);
1584 static struct member *interface_exists(struct call_queue *q, const char *interface);
1585 static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
1586
1587 #if 0   // BUGBUG
1588 static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
1589 #endif  // BUGBUG
1590
1591 static struct member *find_member_by_queuename_and_interface(const char *queuename, const char *interface);
1592 /*! \brief sets the QUEUESTATUS channel variable */
1593 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
1594 {
1595         int i;
1596
1597         for (i = 0; i < ARRAY_LEN(queue_results); i++) {
1598                 if (queue_results[i].id == res) {
1599                         pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
1600                         return;
1601                 }
1602         }
1603 }
1604
1605 static const char *int2strat(int strategy)
1606 {
1607         int x;
1608
1609         for (x = 0; x < ARRAY_LEN(strategies); x++) {
1610                 if (strategy == strategies[x].strategy) {
1611                         return strategies[x].name;
1612                 }
1613         }
1614
1615         return "<unknown>";
1616 }
1617
1618 static int strat2int(const char *strategy)
1619 {
1620         int x;
1621
1622         for (x = 0; x < ARRAY_LEN(strategies); x++) {
1623                 if (!strcasecmp(strategy, strategies[x].name)) {
1624                         return strategies[x].strategy;
1625                 }
1626         }
1627
1628         return -1;
1629 }
1630
1631 static int autopause2int(const char *autopause)
1632 {
1633         int x;
1634         /*This 'double check' that default value is OFF */
1635         if (ast_strlen_zero(autopause)) {
1636                 return QUEUE_AUTOPAUSE_OFF;
1637         }
1638
1639         /*This 'double check' is to ensure old values works */
1640         if(ast_true(autopause)) {
1641                 return QUEUE_AUTOPAUSE_ON;
1642         }
1643
1644         for (x = 0; x < ARRAY_LEN(autopausesmodes); x++) {
1645                 if (!strcasecmp(autopause, autopausesmodes[x].name)) {
1646                         return autopausesmodes[x].autopause;
1647                 }
1648         }
1649
1650         /*This 'double check' that default value is OFF */
1651         return QUEUE_AUTOPAUSE_OFF;
1652 }
1653
1654 static int queue_hash_cb(const void *obj, const int flags)
1655 {
1656         const struct call_queue *q = obj;
1657
1658         return ast_str_case_hash(q->name);
1659 }
1660
1661 static int queue_cmp_cb(void *obj, void *arg, int flags)
1662 {
1663         struct call_queue *q = obj, *q2 = arg;
1664         return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0;
1665 }
1666
1667 /*! \internal
1668  * \brief ao2_callback, Decreases queuepos of all followers with a queuepos greater than arg.
1669  * \param obj the member being acted on
1670  * \param arg pointer to an integer containing the position value that was removed and requires reduction for anything above
1671  */
1672 static int queue_member_decrement_followers(void *obj, void *arg, int flag)
1673 {
1674         struct member *mem = obj;
1675         int *decrement_followers_after = arg;
1676
1677         if (mem->queuepos > *decrement_followers_after) {
1678                 mem->queuepos--;
1679         }
1680
1681         return 0;
1682 }
1683
1684 /*! \internal
1685  * \brief ao2_callback, finds members in a queue marked for deletion and in a cascading fashion runs queue_member_decrement_followers
1686  *        on them. This callback should always be ran before performing mass unlinking of delmarked members from queues.
1687  * \param obj member being acted on
1688  * \param arg pointer to the queue members are being removed from
1689  */
1690 static int queue_delme_members_decrement_followers(void *obj, void *arg, int flag)
1691 {
1692         struct member *mem = obj;
1693         struct call_queue *queue = arg;
1694         int rrpos = mem->queuepos;
1695
1696         if (mem->delme) {
1697                 ao2_callback(queue->members, OBJ_NODATA | OBJ_MULTIPLE, queue_member_decrement_followers, &rrpos);
1698         }
1699
1700         return 0;
1701 }
1702
1703 /*! \internal
1704  * \brief Use this to decrement followers during removal of a member
1705  * \param queue which queue the member is being removed from
1706  * \param mem which member is being removed from the queue
1707  */
1708 static void queue_member_follower_removal(struct call_queue *queue, struct member *mem)
1709 {
1710         int pos = mem->queuepos;
1711
1712         /* 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
1713          * who would have been next otherwise. */
1714         if (pos < queue->rrpos) {
1715                 queue->rrpos--;
1716         }
1717
1718         ao2_callback(queue->members, OBJ_NODATA | OBJ_MULTIPLE, queue_member_decrement_followers, &pos);
1719 }
1720
1721 #ifdef REF_DEBUG_ONLY_QUEUES
1722 #define queue_ref(q)                            _queue_ref(q, "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
1723 #define queue_unref(q)                          _queue_unref(q, "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
1724 #define queue_t_ref(q, tag)                     _queue_ref(q, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
1725 #define queue_t_unref(q, tag)           _queue_unref(q, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
1726 #define queues_t_link(c, q, tag)        __ao2_link_debug(c, q, 0, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
1727 #define queues_t_unlink(c, q, tag)      __ao2_unlink_debug(c, q, 0, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
1728
1729 static inline struct call_queue *_queue_ref(struct call_queue *q, const char *tag, const char *file, int line, const char *filename)
1730 {
1731         __ao2_ref_debug(q, 1, tag, file, line, filename);
1732         return q;
1733 }
1734
1735 static inline struct call_queue *_queue_unref(struct call_queue *q, const char *tag, const char *file, int line, const char *filename)
1736 {
1737         __ao2_ref_debug(q, -1, tag, file, line, filename);
1738         return NULL;
1739 }
1740
1741 #else
1742
1743 #define queue_t_ref(q, tag)                     queue_ref(q)
1744 #define queue_t_unref(q, tag)           queue_unref(q)
1745 #define queues_t_link(c, q, tag)        ao2_t_link(c, q, tag)
1746 #define queues_t_unlink(c, q, tag)      ao2_t_unlink(c, q, tag)
1747
1748 static inline struct call_queue *queue_ref(struct call_queue *q)
1749 {
1750         ao2_ref(q, 1);
1751         return q;
1752 }
1753
1754 static inline struct call_queue *queue_unref(struct call_queue *q)
1755 {
1756         ao2_ref(q, -1);
1757         return NULL;
1758 }
1759 #endif
1760
1761 /*! \brief Set variables of queue */
1762 static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
1763 {
1764         char interfacevar[256]="";
1765         float sl = 0;
1766
1767         ao2_lock(q);
1768
1769         if (q->setqueuevar) {
1770                 sl = 0;
1771                 if (q->callscompleted > 0) {
1772                         sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
1773                 }
1774
1775                 snprintf(interfacevar, sizeof(interfacevar),
1776                         "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
1777                         q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned,  q->servicelevel, sl);
1778
1779                 ao2_unlock(q);
1780
1781                 pbx_builtin_setvar_multiple(chan, interfacevar);
1782         } else {
1783                 ao2_unlock(q);
1784         }
1785 }
1786
1787 /*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
1788 static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
1789 {
1790         struct queue_ent *cur;
1791
1792         if (!q || !new)
1793                 return;
1794         if (prev) {
1795                 cur = prev->next;
1796                 prev->next = new;
1797         } else {
1798                 cur = q->head;
1799                 q->head = new;
1800         }
1801         new->next = cur;
1802
1803         /* every queue_ent must have a reference to it's parent call_queue, this
1804          * reference does not go away until the end of the queue_ent's life, meaning
1805          * that even when the queue_ent leaves the call_queue this ref must remain. */
1806         queue_ref(q);
1807         new->parent = q;
1808         new->pos = ++(*pos);
1809         new->opos = *pos;
1810 }
1811
1812 STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_caller_join_type);
1813 STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_caller_leave_type);
1814 STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_caller_abandon_type);
1815
1816 STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_status_type);
1817 STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_added_type);
1818 STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_removed_type);
1819 STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_pause_type);
1820 STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_penalty_type);
1821 STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_ringinuse_type);
1822
1823 STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_called_type);
1824 STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_connect_type);
1825 STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_complete_type);
1826 STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_dump_type);
1827 STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_ringnoanswer_type);
1828
1829 static void queue_channel_manager_event(void *data,
1830         struct stasis_subscription *sub, struct stasis_topic *topic,
1831         struct stasis_message *message)
1832 {
1833         const char *type = data;
1834         struct ast_channel_blob *obj = stasis_message_data(message);
1835         RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
1836         RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
1837
1838         channel_event_string = ast_manager_build_channel_state_string(obj->snapshot);
1839         if (!channel_event_string) {
1840                 return;
1841         }
1842
1843         event_string = ast_manager_str_from_json_object(obj->blob, NULL);
1844         if (!event_string) {
1845                 return;
1846         }
1847
1848         manager_event(EVENT_FLAG_AGENT, type,
1849                 "%s"
1850                 "%s",
1851                 ast_str_buffer(channel_event_string),
1852                 ast_str_buffer(event_string));
1853 }
1854
1855 static void queue_multi_channel_manager_event(void *data,
1856         struct stasis_subscription *sub, struct stasis_topic *topic,
1857         struct stasis_message *message)
1858 {
1859         const char *type = data;
1860         struct ast_multi_channel_blob *obj = stasis_message_data(message);
1861         struct ast_channel_snapshot *caller;
1862         struct ast_channel_snapshot *agent;
1863         RAII_VAR(struct ast_str *, caller_event_string, NULL, ast_free);
1864         RAII_VAR(struct ast_str *, agent_event_string, NULL, ast_free);
1865         RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
1866
1867         caller = ast_multi_channel_blob_get_channel(obj, "caller");
1868         agent = ast_multi_channel_blob_get_channel(obj, "agent");
1869
1870         caller_event_string = ast_manager_build_channel_state_string(caller);
1871         agent_event_string = ast_manager_build_channel_state_string_prefix(agent, "Dest");
1872
1873         if (!caller_event_string || !agent_event_string) {
1874                 return;
1875         }
1876
1877         event_string = ast_manager_str_from_json_object(ast_multi_channel_blob_get_json(obj), NULL);
1878         if (!event_string) {
1879                 return;
1880         }
1881
1882         manager_event(EVENT_FLAG_AGENT, type,
1883                 "%s"
1884                 "%s"
1885                 "%s",
1886                 ast_str_buffer(caller_event_string),
1887                 ast_str_buffer(agent_event_string),
1888                 ast_str_buffer(event_string));
1889 }
1890
1891 static void queue_member_manager_event(void *data,
1892         struct stasis_subscription *sub, struct stasis_topic *topic,
1893         struct stasis_message *message)
1894 {
1895         const char *type = data;
1896         struct ast_json_payload *payload = stasis_message_data(message);
1897         struct ast_json *event = payload->json;
1898         RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
1899
1900         event_string = ast_manager_str_from_json_object(event, NULL);
1901         if (!event_string) {
1902                 return;
1903         }
1904
1905         manager_event(EVENT_FLAG_AGENT, type,
1906                 "%s", ast_str_buffer(event_string));
1907 }
1908
1909 static void queue_publish_multi_channel_blob(struct ast_channel *caller, struct ast_channel *agent, struct stasis_message_type *type, struct ast_json *blob)
1910 {
1911         RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
1912         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
1913         struct ast_channel_snapshot *caller_snapshot;
1914         struct ast_channel_snapshot *agent_snapshot;
1915
1916         payload = ast_multi_channel_blob_create(blob);
1917         if (!payload) {
1918                 return;
1919         }
1920
1921         caller_snapshot = ast_channel_snapshot_create(caller);
1922         agent_snapshot = ast_channel_snapshot_create(agent);
1923
1924         if (!caller_snapshot || !agent_snapshot) {
1925                 return;
1926         }
1927
1928         ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot);
1929         ast_multi_channel_blob_add_channel(payload, "agent", agent_snapshot);
1930
1931         msg = stasis_message_create(type, payload);
1932         if (!msg) {
1933                 return;
1934         }
1935
1936         stasis_publish(ast_channel_topic(caller), msg);
1937 }
1938
1939 static void queue_publish_member_blob(struct stasis_message_type *type, struct ast_json *blob)
1940 {
1941         RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
1942         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
1943
1944         payload = ast_json_payload_create(blob);
1945         if (!payload) {
1946                 return;
1947         }
1948
1949         msg = stasis_message_create(type, payload);
1950         if (!msg) {
1951                 return;
1952         }
1953
1954         stasis_publish(ast_manager_get_topic(), msg);
1955 }
1956
1957 static struct ast_json *queue_member_blob_create(struct call_queue *q, struct member *mem)
1958 {
1959         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}",
1960                 "Queue", q->name,
1961                 "MemberName", mem->membername,
1962                 "Interface", mem->interface,
1963                 "StateInterface", mem->state_interface,
1964                 "Membership", (mem->dynamic ? "dynamic" : (mem->realtime ? "realtime" : "static")),
1965                 "Penalty", mem->penalty,
1966                 "CallsTaken", mem->calls,
1967                 "LastCall", (int)mem->lastcall,
1968                 "Status", mem->status,
1969                 "Paused", mem->paused,
1970                 "Ringinuse", mem->ringinuse);
1971 }
1972
1973 /*! \brief Check if members are available
1974  *
1975  * This function checks to see if members are available to be called. If any member
1976  * is available, the function immediately returns 0. If no members are available,
1977  * then -1 is returned.
1978  */
1979 static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, enum empty_conditions conditions)
1980 {
1981         struct member *member;
1982         struct ao2_iterator mem_iter;
1983
1984         ao2_lock(q);
1985         mem_iter = ao2_iterator_init(q->members, 0);
1986         for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
1987                 if ((max_penalty && (member->penalty > max_penalty)) || (min_penalty && (member->penalty < min_penalty))) {
1988                         if (conditions & QUEUE_EMPTY_PENALTY) {
1989                                 ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
1990                                 continue;
1991                         }
1992                 }
1993
1994                 switch (member->status) {
1995                 case AST_DEVICE_INVALID:
1996                         if (conditions & QUEUE_EMPTY_INVALID) {
1997                                 ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername);
1998                                 break;
1999                         }
2000                         goto default_case;
2001                 case AST_DEVICE_UNAVAILABLE:
2002                         if (conditions & QUEUE_EMPTY_UNAVAILABLE) {
2003                                 ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername);
2004                                 break;
2005                         }
2006                         goto default_case;
2007                 case AST_DEVICE_INUSE:
2008                         if (conditions & QUEUE_EMPTY_INUSE) {
2009                                 ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername);
2010                                 break;
2011                         }
2012                         goto default_case;
2013                 case AST_DEVICE_RINGING:
2014                         if (conditions & QUEUE_EMPTY_RINGING) {
2015                                 ast_debug(4, "%s is unavailable because his device state is 'ringing'\n", member->membername);
2016                                 break;
2017                         }
2018                         goto default_case;
2019                 case AST_DEVICE_UNKNOWN:
2020                         if (conditions & QUEUE_EMPTY_UNKNOWN) {
2021                                 ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername);
2022                                 break;
2023                         }
2024                         /* Fall-through */
2025                 default:
2026                 default_case:
2027                         if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) {
2028                                 ast_debug(4, "%s is unavailable because he is paused'\n", member->membername);
2029                                 break;
2030                         } else if ((conditions & QUEUE_EMPTY_WRAPUP) && member->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < member->lastcall)) {
2031                                 ast_debug(4, "%s is unavailable because it has only been %d seconds since his last call (wrapup time is %d)\n", member->membername, (int) (time(NULL) - member->lastcall), q->wrapuptime);
2032                                 break;
2033                         } else {
2034                                 ao2_ref(member, -1);
2035                                 ao2_iterator_destroy(&mem_iter);
2036                                 ao2_unlock(q);
2037                                 ast_debug(4, "%s is available.\n", member->membername);
2038                                 return 0;
2039                         }
2040                         break;
2041                 }
2042         }
2043         ao2_iterator_destroy(&mem_iter);
2044
2045         ao2_unlock(q);
2046         return -1;
2047 }
2048
2049 /*! \brief set a member's status based on device state of that member's state_interface.
2050  *
2051  * Lock interface list find sc, iterate through each queues queue_member list for member to
2052  * update state inside queues
2053 */
2054 static void update_status(struct call_queue *q, struct member *m, const int status)
2055 {
2056         m->status = status;
2057
2058         queue_publish_member_blob(queue_member_status_type(), queue_member_blob_create(q, m));
2059 }
2060
2061 /*!
2062  * \internal
2063  * \brief Determine if a queue member is available
2064  * \retval 1 if the member is available
2065  * \retval 0 if the member is not available
2066  */
2067 static int is_member_available(struct call_queue *q, struct member *mem)
2068 {
2069         int available = 0;
2070
2071         switch (mem->status) {
2072                 case AST_DEVICE_INVALID:
2073                 case AST_DEVICE_UNAVAILABLE:
2074                         break;
2075                 case AST_DEVICE_INUSE:
2076                 case AST_DEVICE_BUSY:
2077                 case AST_DEVICE_RINGING:
2078                 case AST_DEVICE_RINGINUSE:
2079                 case AST_DEVICE_ONHOLD:
2080                         if (!mem->ringinuse) {
2081                                 break;
2082                         }
2083                         /* else fall through */
2084                 case AST_DEVICE_NOT_INUSE:
2085                 case AST_DEVICE_UNKNOWN:
2086                         if (!mem->paused) {
2087                                 available = 1;
2088                         }
2089                         break;
2090         }
2091
2092         /* Let wrapuptimes override device state availability */
2093         if (mem->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < mem->lastcall)) {
2094                 available = 0;
2095         }
2096         return available;
2097 }
2098
2099 /*! \brief set a member's status based on device state of that member's interface*/
2100 static void device_state_cb(void *unused, struct stasis_subscription *sub, struct stasis_topic *topic, struct stasis_message *msg)
2101 {
2102         struct ao2_iterator miter, qiter;
2103         struct ast_device_state_message *dev_state;
2104         struct member *m;
2105         struct call_queue *q;
2106         char interface[80], *slash_pos;
2107         int found = 0;                  /* Found this member in any queue */
2108         int found_member;               /* Found this member in this queue */
2109         int avail = 0;                  /* Found an available member in this queue */
2110
2111         if (ast_device_state_message_type() != stasis_message_type(msg)) {
2112                 return;
2113         }
2114
2115         dev_state = stasis_message_data(msg);
2116         if (dev_state->eid) {
2117                 /* ignore non-aggregate states */
2118                 return;
2119         }
2120
2121         qiter = ao2_iterator_init(queues, 0);
2122         while ((q = ao2_t_iterator_next(&qiter, "Iterate over queues"))) {
2123                 ao2_lock(q);
2124
2125                 avail = 0;
2126                 found_member = 0;
2127                 miter = ao2_iterator_init(q->members, 0);
2128                 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
2129                         if (!found_member) {
2130                                 ast_copy_string(interface, m->state_interface, sizeof(interface));
2131
2132                                 if ((slash_pos = strchr(interface, '/'))) {
2133                                         if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/'))) {
2134                                                 *slash_pos = '\0';
2135                                         }
2136                                 }
2137
2138                                 if (!strcasecmp(interface, dev_state->device)) {
2139                                         found_member = 1;
2140                                         update_status(q, m, dev_state->state);
2141                                 }
2142                         }
2143
2144                         /* check every member until we find one NOT_INUSE */
2145                         if (!avail) {
2146                                 avail = is_member_available(q, m);
2147                         }
2148                         if (avail && found_member) {
2149                                 /* early exit as we've found an available member and the member of interest */
2150                                 ao2_ref(m, -1);
2151                                 break;
2152                         }
2153                 }
2154
2155                 if (found_member) {
2156                         found = 1;
2157                         if (avail) {
2158                                 ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name);
2159                         } else {
2160                                 ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name);
2161                         }
2162                 }
2163
2164                 ao2_iterator_destroy(&miter);
2165
2166                 ao2_unlock(q);
2167                 queue_t_unref(q, "Done with iterator");
2168         }
2169         ao2_iterator_destroy(&qiter);
2170
2171         if (found) {
2172                 ast_debug(1, "Device '%s' changed to state '%d' (%s)\n",
2173                         dev_state->device,
2174                         dev_state->state,
2175                         ast_devstate2str(dev_state->state));
2176         } else {
2177                 ast_debug(3, "Device '%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n",
2178                         dev_state->device,
2179                         dev_state->state,
2180                         ast_devstate2str(dev_state->state));
2181         }
2182
2183         return;
2184 }
2185
2186 /*! \brief Helper function which converts from extension state to device state values */
2187 static int extensionstate2devicestate(int state)
2188 {
2189         switch (state) {
2190         case AST_EXTENSION_NOT_INUSE:
2191                 state = AST_DEVICE_NOT_INUSE;
2192                 break;
2193         case AST_EXTENSION_INUSE:
2194                 state = AST_DEVICE_INUSE;
2195                 break;
2196         case AST_EXTENSION_BUSY:
2197                 state = AST_DEVICE_BUSY;
2198                 break;
2199         case AST_EXTENSION_RINGING:
2200                 state = AST_DEVICE_RINGING;
2201                 break;
2202         case AST_EXTENSION_ONHOLD:
2203                 state = AST_DEVICE_ONHOLD;
2204                 break;
2205         case AST_EXTENSION_UNAVAILABLE:
2206                 state = AST_DEVICE_UNAVAILABLE;
2207                 break;
2208         case AST_EXTENSION_REMOVED:
2209         case AST_EXTENSION_DEACTIVATED:
2210         default:
2211                 state = AST_DEVICE_INVALID;
2212                 break;
2213         }
2214
2215         return state;
2216 }
2217
2218 static int extension_state_cb(char *context, char *exten, struct ast_state_cb_info *info, void *data)
2219 {
2220         struct ao2_iterator miter, qiter;
2221         struct member *m;
2222         struct call_queue *q;
2223         int state = info->exten_state;
2224         int found = 0, device_state = extensionstate2devicestate(state);
2225
2226         /* only interested in extension state updates involving device states */
2227         if (info->reason != AST_HINT_UPDATE_DEVICE) {
2228                 return 0;
2229         }
2230
2231         qiter = ao2_iterator_init(queues, 0);
2232         while ((q = ao2_t_iterator_next(&qiter, "Iterate through queues"))) {
2233                 ao2_lock(q);
2234
2235                 miter = ao2_iterator_init(q->members, 0);
2236                 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
2237                         if (!strcmp(m->state_context, context) && !strcmp(m->state_exten, exten)) {
2238                                 update_status(q, m, device_state);
2239                                 ao2_ref(m, -1);
2240                                 found = 1;
2241                                 break;
2242                         }
2243                 }
2244                 ao2_iterator_destroy(&miter);
2245
2246                 ao2_unlock(q);
2247                 queue_t_unref(q, "Done with iterator");
2248         }
2249         ao2_iterator_destroy(&qiter);
2250
2251         if (found) {
2252                 ast_debug(1, "Extension '%s@%s' changed to state '%d' (%s)\n", exten, context, device_state, ast_devstate2str(device_state));
2253         } else {
2254                 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",
2255                           exten, context, device_state, ast_devstate2str(device_state));
2256         }
2257
2258         return 0;
2259 }
2260
2261 /*! \brief Return the current state of a member */
2262 static int get_queue_member_status(struct member *cur)
2263 {
2264         return ast_strlen_zero(cur->state_exten) ? ast_device_state(cur->state_interface) : extensionstate2devicestate(ast_extension_state(NULL, cur->state_context, cur->state_exten));
2265 }
2266
2267 /*! \brief allocate space for new queue member and set fields based on parameters passed */
2268 static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface, int ringinuse)
2269 {
2270         struct member *cur;
2271
2272         if ((cur = ao2_alloc(sizeof(*cur), NULL))) {
2273                 cur->ringinuse = ringinuse;
2274                 cur->penalty = penalty;
2275                 cur->paused = paused;
2276                 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
2277                 if (!ast_strlen_zero(state_interface)) {
2278                         ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface));
2279                 } else {
2280                         ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface));
2281                 }
2282                 if (!ast_strlen_zero(membername)) {
2283                         ast_copy_string(cur->membername, membername, sizeof(cur->membername));
2284                 } else {
2285                         ast_copy_string(cur->membername, interface, sizeof(cur->membername));
2286                 }
2287                 if (!strchr(cur->interface, '/')) {
2288                         ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
2289                 }
2290                 if (!strncmp(cur->state_interface, "hint:", 5)) {
2291                         char *tmp = ast_strdupa(cur->state_interface), *context = tmp;
2292                         char *exten = strsep(&context, "@") + 5;
2293
2294                         ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten));
2295                         ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context));
2296                 }
2297                 cur->status = get_queue_member_status(cur);
2298         }
2299
2300         return cur;
2301 }
2302
2303
2304 static int compress_char(const char c)
2305 {
2306         if (c < 32) {
2307                 return 0;
2308         } else if (c > 96) {
2309                 return c - 64;
2310         }
2311         return c - 32;
2312 }
2313
2314 static int member_hash_fn(const void *obj, const int flags)
2315 {
2316         const struct member *mem = obj;
2317         const char *interface = (flags & OBJ_KEY) ? obj : mem->interface;
2318         const char *chname = strchr(interface, '/');
2319         int ret = 0, i;
2320
2321         if (!chname) {
2322                 chname = interface;
2323         }
2324         for (i = 0; i < 5 && chname[i]; i++) {
2325                 ret += compress_char(chname[i]) << (i * 6);
2326         }
2327         return ret;
2328 }
2329
2330 static int member_cmp_fn(void *obj1, void *obj2, int flags)
2331 {
2332         struct member *mem1 = obj1;
2333         struct member *mem2 = obj2;
2334         const char *interface = (flags & OBJ_KEY) ? obj2 : mem2->interface;
2335
2336         return strcasecmp(mem1->interface, interface) ? 0 : CMP_MATCH | CMP_STOP;
2337 }
2338
2339 /*!
2340  * \brief Initialize Queue default values.
2341  * \note the queue's lock  must be held before executing this function
2342 */
2343 static void init_queue(struct call_queue *q)
2344 {
2345         int i;
2346         struct penalty_rule *pr_iter;
2347
2348         q->dead = 0;
2349         q->retry = DEFAULT_RETRY;
2350         q->timeout = DEFAULT_TIMEOUT;
2351         q->maxlen = 0;
2352         q->announcefrequency = 0;
2353         q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY;
2354         q->announceholdtime = 1;
2355         q->announcepositionlimit = 10; /* Default 10 positions */
2356         q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */
2357         q->roundingseconds = 0; /* Default - don't announce seconds */
2358         q->servicelevel = 0;
2359         q->ringinuse = 1;
2360         q->announce_to_first_user = 0;
2361         q->setinterfacevar = 0;
2362         q->setqueuevar = 0;
2363         q->setqueueentryvar = 0;
2364         q->autofill = autofill_default;
2365         q->montype = montype_default;
2366         q->monfmt[0] = '\0';
2367         q->reportholdtime = 0;
2368         q->wrapuptime = 0;
2369         q->penaltymemberslimit = 0;
2370         q->joinempty = 0;
2371         q->leavewhenempty = 0;
2372         q->memberdelay = 0;
2373         q->weight = 0;
2374         q->timeoutrestart = 0;
2375         q->periodicannouncefrequency = 0;
2376         q->randomperiodicannounce = 0;
2377         q->numperiodicannounce = 0;
2378         q->autopause = QUEUE_AUTOPAUSE_OFF;
2379         q->timeoutpriority = TIMEOUT_PRIORITY_APP;
2380         q->autopausedelay = 0;
2381         if (!q->members) {
2382                 if (q->strategy == QUEUE_STRATEGY_LINEAR || q->strategy == QUEUE_STRATEGY_RRORDERED) {
2383                         /* linear strategy depends on order, so we have to place all members in a single bucket */
2384                         q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn);
2385                 } else {
2386                         q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
2387                 }
2388         }
2389         q->found = 1;
2390
2391         ast_string_field_set(q, sound_next, "queue-youarenext");
2392         ast_string_field_set(q, sound_thereare, "queue-thereare");
2393         ast_string_field_set(q, sound_calls, "queue-callswaiting");
2394         ast_string_field_set(q, queue_quantity1, "queue-quantity1");
2395         ast_string_field_set(q, queue_quantity2, "queue-quantity2");
2396         ast_string_field_set(q, sound_holdtime, "queue-holdtime");
2397         ast_string_field_set(q, sound_minutes, "queue-minutes");
2398         ast_string_field_set(q, sound_minute, "queue-minute");
2399         ast_string_field_set(q, sound_seconds, "queue-seconds");
2400         ast_string_field_set(q, sound_thanks, "queue-thankyou");
2401         ast_string_field_set(q, sound_reporthold, "queue-reporthold");
2402
2403         if (!q->sound_periodicannounce[0]) {
2404                 q->sound_periodicannounce[0] = ast_str_create(32);
2405         }
2406
2407         if (q->sound_periodicannounce[0]) {
2408                 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
2409         }
2410
2411         for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
2412                 if (q->sound_periodicannounce[i]) {
2413                         ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
2414                 }
2415         }
2416
2417         while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list))) {
2418                 ast_free(pr_iter);
2419         }
2420
2421         /* On restart assume no members are available.
2422          * The queue_avail hint is a boolean state to indicate whether a member is available or not.
2423          *
2424          * This seems counter intuitive, but is required to light a BLF
2425          * AST_DEVICE_INUSE indicates no members are available.
2426          * AST_DEVICE_NOT_INUSE indicates a member is available.
2427          */
2428         ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name);
2429 }
2430
2431 static void clear_queue(struct call_queue *q)
2432 {
2433         q->holdtime = 0;
2434         q->callscompleted = 0;
2435         q->callsabandoned = 0;
2436         q->callscompletedinsl = 0;
2437         q->talktime = 0;
2438
2439         if (q->members) {
2440                 struct member *mem;
2441                 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
2442                 while ((mem = ao2_iterator_next(&mem_iter))) {
2443                         mem->calls = 0;
2444                         mem->lastcall = 0;
2445                         ao2_ref(mem, -1);
2446                 }
2447                 ao2_iterator_destroy(&mem_iter);
2448         }
2449 }
2450
2451 /*!
2452  * \brief Change queue penalty by adding rule.
2453  *
2454  * Check rule for errors with time or fomatting, see if rule is relative to rest
2455  * of queue, iterate list of rules to find correct insertion point, insert and return.
2456  * \retval -1 on failure
2457  * \retval 0 on success
2458  * \note Call this with the rule_lists locked
2459 */
2460 static int insert_penaltychange(const char *list_name, const char *content, const int linenum)
2461 {
2462         char *timestr, *maxstr, *minstr, *contentdup;
2463         struct penalty_rule *rule = NULL, *rule_iter;
2464         struct rule_list *rl_iter;
2465         int penaltychangetime, inserted = 0;
2466
2467         if (!(rule = ast_calloc(1, sizeof(*rule)))) {
2468                 return -1;
2469         }
2470
2471         contentdup = ast_strdupa(content);
2472
2473         if (!(maxstr = strchr(contentdup, ','))) {
2474                 ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum);
2475                 ast_free(rule);
2476                 return -1;
2477         }
2478
2479         *maxstr++ = '\0';
2480         timestr = contentdup;
2481
2482         if ((penaltychangetime = atoi(timestr)) < 0) {
2483                 ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum);
2484                 ast_free(rule);
2485                 return -1;
2486         }
2487
2488         rule->time = penaltychangetime;
2489
2490         if ((minstr = strchr(maxstr,','))) {
2491                 *minstr++ = '\0';
2492         }
2493
2494         /* The last check will evaluate true if either no penalty change is indicated for a given rule
2495          * OR if a min penalty change is indicated but no max penalty change is */
2496         if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') {
2497                 rule->max_relative = 1;
2498         }
2499
2500         rule->max_value = atoi(maxstr);
2501
2502         if (!ast_strlen_zero(minstr)) {
2503                 if (*minstr == '+' || *minstr == '-') {
2504                         rule->min_relative = 1;
2505                 }
2506                 rule->min_value = atoi(minstr);
2507         } else { /*there was no minimum specified, so assume this means no change*/
2508                 rule->min_relative = 1;
2509         }
2510
2511         /*We have the rule made, now we need to insert it where it belongs*/
2512         AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){
2513                 if (strcasecmp(rl_iter->name, list_name)) {
2514                         continue;
2515                 }
2516
2517                 AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) {
2518                         if (rule->time < rule_iter->time) {
2519                                 AST_LIST_INSERT_BEFORE_CURRENT(rule, list);
2520                                 inserted = 1;
2521                                 break;
2522                         }
2523                 }
2524                 AST_LIST_TRAVERSE_SAFE_END;
2525
2526                 if (!inserted) {
2527                         AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list);
2528                         inserted = 1;
2529                 }
2530
2531                 break;
2532         }
2533
2534         if (!inserted) {
2535                 ast_log(LOG_WARNING, "Unknown rule list name %s; ignoring.\n", list_name);
2536                 ast_free(rule);
2537                 return -1;
2538         }
2539         return 0;
2540 }
2541
2542 static void parse_empty_options(const char *value, enum empty_conditions *empty, int joinempty)
2543 {
2544         char *value_copy = ast_strdupa(value);
2545         char *option = NULL;
2546         while ((option = strsep(&value_copy, ","))) {
2547                 if (!strcasecmp(option, "paused")) {
2548                         *empty |= QUEUE_EMPTY_PAUSED;
2549                 } else if (!strcasecmp(option, "penalty")) {
2550                         *empty |= QUEUE_EMPTY_PENALTY;
2551                 } else if (!strcasecmp(option, "inuse")) {
2552                         *empty |= QUEUE_EMPTY_INUSE;
2553                 } else if (!strcasecmp(option, "ringing")) {
2554                         *empty |= QUEUE_EMPTY_RINGING;
2555                 } else if (!strcasecmp(option, "invalid")) {
2556                         *empty |= QUEUE_EMPTY_INVALID;
2557                 } else if (!strcasecmp(option, "wrapup")) {
2558                         *empty |= QUEUE_EMPTY_WRAPUP;
2559                 } else if (!strcasecmp(option, "unavailable")) {
2560                         *empty |= QUEUE_EMPTY_UNAVAILABLE;
2561                 } else if (!strcasecmp(option, "unknown")) {
2562                         *empty |= QUEUE_EMPTY_UNKNOWN;
2563                 } else if (!strcasecmp(option, "loose")) {
2564                         *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID);
2565                 } else if (!strcasecmp(option, "strict")) {
2566                         *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED | QUEUE_EMPTY_UNAVAILABLE);
2567                 } else if ((ast_false(option) && joinempty) || (ast_true(option) && !joinempty)) {
2568                         *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED);
2569                 } else if ((ast_false(option) && !joinempty) || (ast_true(option) && joinempty)) {
2570                         *empty = 0;
2571                 } else {
2572                         ast_log(LOG_WARNING, "Unknown option %s for '%s'\n", option, joinempty ? "joinempty" : "leavewhenempty");
2573                 }
2574         }
2575 }
2576
2577 /*! \brief Configure a queue parameter.
2578  *
2579  * The failunknown flag is set for config files (and static realtime) to show
2580  * errors for unknown parameters. It is cleared for dynamic realtime to allow
2581  *  extra fields in the tables.
2582  * \note For error reporting, line number is passed for .conf static configuration,
2583  * for Realtime queues, linenum is -1.
2584 */
2585 static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
2586 {
2587         if (!strcasecmp(param, "musicclass") ||
2588                 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
2589                 ast_string_field_set(q, moh, val);
2590         } else if (!strcasecmp(param, "announce")) {
2591                 ast_string_field_set(q, announce, val);
2592         } else if (!strcasecmp(param, "context")) {
2593                 ast_string_field_set(q, context, val);
2594         } else if (!strcasecmp(param, "timeout")) {
2595                 q->timeout = atoi(val);
2596                 if (q->timeout < 0) {
2597                         q->timeout = DEFAULT_TIMEOUT;
2598                 }
2599         } else if (!strcasecmp(param, "ringinuse")) {
2600                 q->ringinuse = ast_true(val);
2601         } else if (!strcasecmp(param, "setinterfacevar")) {
2602                 q->setinterfacevar = ast_true(val);
2603         } else if (!strcasecmp(param, "setqueuevar")) {
2604                 q->setqueuevar = ast_true(val);
2605         } else if (!strcasecmp(param, "setqueueentryvar")) {
2606                 q->setqueueentryvar = ast_true(val);
2607         } else if (!strcasecmp(param, "monitor-format")) {
2608                 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
2609         } else if (!strcasecmp(param, "membermacro")) {
2610                 ast_string_field_set(q, membermacro, val);
2611         } else if (!strcasecmp(param, "membergosub")) {
2612                 ast_string_field_set(q, membergosub, val);
2613         } else if (!strcasecmp(param, "queue-youarenext")) {
2614                 ast_string_field_set(q, sound_next, val);
2615         } else if (!strcasecmp(param, "queue-thereare")) {
2616                 ast_string_field_set(q, sound_thereare, val);
2617         } else if (!strcasecmp(param, "queue-callswaiting")) {
2618                 ast_string_field_set(q, sound_calls, val);
2619         } else if (!strcasecmp(param, "queue-quantity1")) {
2620                 ast_string_field_set(q, queue_quantity1, val);
2621         } else if (!strcasecmp(param, "queue-quantity2")) {
2622                 ast_string_field_set(q, queue_quantity2, val);
2623         } else if (!strcasecmp(param, "queue-holdtime")) {
2624                 ast_string_field_set(q, sound_holdtime, val);
2625         } else if (!strcasecmp(param, "queue-minutes")) {
2626                 ast_string_field_set(q, sound_minutes, val);
2627         } else if (!strcasecmp(param, "queue-minute")) {
2628                 ast_string_field_set(q, sound_minute, val);
2629         } else if (!strcasecmp(param, "queue-seconds")) {
2630                 ast_string_field_set(q, sound_seconds, val);
2631         } else if (!strcasecmp(param, "queue-thankyou")) {
2632                 ast_string_field_set(q, sound_thanks, val);
2633         } else if (!strcasecmp(param, "queue-callerannounce")) {
2634                 ast_string_field_set(q, sound_callerannounce, val);
2635         } else if (!strcasecmp(param, "queue-reporthold")) {
2636                 ast_string_field_set(q, sound_reporthold, val);
2637         } else if (!strcasecmp(param, "announce-frequency")) {
2638                 q->announcefrequency = atoi(val);
2639         } else if (!strcasecmp(param, "announce-to-first-user")) {
2640                 q->announce_to_first_user = ast_true(val);
2641         } else if (!strcasecmp(param, "min-announce-frequency")) {
2642                 q->minannouncefrequency = atoi(val);
2643                 ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name);
2644         } else if (!strcasecmp(param, "announce-round-seconds")) {
2645                 q->roundingseconds = atoi(val);
2646                 /* Rounding to any other values just doesn't make sense... */
2647                 if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10
2648                         || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) {
2649                         if (linenum >= 0) {
2650                                 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
2651                                         "using 0 instead for queue '%s' at line %d of queues.conf\n",
2652                                         val, param, q->name, linenum);
2653                         } else {
2654                                 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
2655                                         "using 0 instead for queue '%s'\n", val, param, q->name);
2656                         }
2657                         q->roundingseconds=0;
2658                 }
2659         } else if (!strcasecmp(param, "announce-holdtime")) {
2660                 if (!strcasecmp(val, "once")) {
2661                         q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
2662                 } else if (ast_true(val)) {
2663                         q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
2664                 } else {
2665                         q->announceholdtime = 0;
2666                 }
2667         } else if (!strcasecmp(param, "announce-position")) {
2668                 if (!strcasecmp(val, "limit")) {
2669                         q->announceposition = ANNOUNCEPOSITION_LIMIT;
2670                 } else if (!strcasecmp(val, "more")) {
2671                         q->announceposition = ANNOUNCEPOSITION_MORE_THAN;
2672                 } else if (ast_true(val)) {
2673                         q->announceposition = ANNOUNCEPOSITION_YES;
2674                 } else {
2675                         q->announceposition = ANNOUNCEPOSITION_NO;
2676                 }
2677         } else if (!strcasecmp(param, "announce-position-limit")) {
2678                 q->announcepositionlimit = atoi(val);
2679         } else if (!strcasecmp(param, "periodic-announce")) {
2680                 if (strchr(val, ',')) {
2681                         char *s, *buf = ast_strdupa(val);
2682                         unsigned int i = 0;
2683
2684                         while ((s = strsep(&buf, ",|"))) {
2685                                 if (!q->sound_periodicannounce[i]) {
2686                                         q->sound_periodicannounce[i] = ast_str_create(16);
2687                                 }
2688                                 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s);
2689                                 i++;
2690                                 if (i == MAX_PERIODIC_ANNOUNCEMENTS) {
2691                                         break;
2692                                 }
2693                         }
2694                         q->numperiodicannounce = i;
2695                 } else {
2696                         ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val);
2697                         q->numperiodicannounce = 1;
2698                 }
2699         } else if (!strcasecmp(param, "periodic-announce-frequency")) {
2700                 q->periodicannouncefrequency = atoi(val);
2701         } else if (!strcasecmp(param, "relative-periodic-announce")) {
2702                 q->relativeperiodicannounce = ast_true(val);
2703         } else if (!strcasecmp(param, "random-periodic-announce")) {
2704                 q->randomperiodicannounce = ast_true(val);
2705         } else if (!strcasecmp(param, "retry")) {
2706                 q->retry = atoi(val);
2707                 if (q->retry <= 0) {
2708                         q->retry = DEFAULT_RETRY;
2709                 }
2710         } else if (!strcasecmp(param, "wrapuptime")) {
2711                 q->wrapuptime = atoi(val);
2712         } else if (!strcasecmp(param, "penaltymemberslimit")) {
2713                 if ((sscanf(val, "%10d", &q->penaltymemberslimit) != 1)) {
2714                         q->penaltymemberslimit = 0;
2715                 }
2716         } else if (!strcasecmp(param, "autofill")) {
2717                 q->autofill = ast_true(val);
2718         } else if (!strcasecmp(param, "monitor-type")) {
2719                 if (!strcasecmp(val, "mixmonitor")) {
2720                         q->montype = 1;
2721                 }
2722         } else if (!strcasecmp(param, "autopause")) {
2723                 q->autopause = autopause2int(val);
2724         } else if (!strcasecmp(param, "autopausedelay")) {
2725                 q->autopausedelay = atoi(val);
2726         } else if (!strcasecmp(param, "autopausebusy")) {
2727                 q->autopausebusy = ast_true(val);
2728         } else if (!strcasecmp(param, "autopauseunavail")) {
2729                 q->autopauseunavail = ast_true(val);
2730         } else if (!strcasecmp(param, "maxlen")) {
2731                 q->maxlen = atoi(val);
2732                 if (q->maxlen < 0) {
2733                         q->maxlen = 0;
2734                 }
2735         } else if (!strcasecmp(param, "servicelevel")) {
2736                 q->servicelevel= atoi(val);
2737         } else if (!strcasecmp(param, "strategy")) {
2738                 int strategy;
2739
2740                 /* We are a static queue and already have set this, no need to do it again */
2741                 if (failunknown) {
2742                         return;
2743                 }
2744                 strategy = strat2int(val);
2745                 if (strategy < 0) {
2746                         ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
2747                                 val, q->name);
2748                         q->strategy = QUEUE_STRATEGY_RINGALL;
2749                 }
2750                 if (strategy == q->strategy) {
2751                         return;
2752                 }
2753                 if (strategy == QUEUE_STRATEGY_LINEAR) {
2754                         ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n");
2755                         return;
2756                 }
2757                 q->strategy = strategy;
2758         } else if (!strcasecmp(param, "joinempty")) {
2759                 parse_empty_options(val, &q->joinempty, 1);
2760         } else if (!strcasecmp(param, "leavewhenempty")) {
2761                 parse_empty_options(val, &q->leavewhenempty, 0);
2762         } else if (!strcasecmp(param, "reportholdtime")) {
2763                 q->reportholdtime = ast_true(val);
2764         } else if (!strcasecmp(param, "memberdelay")) {
2765                 q->memberdelay = atoi(val);
2766         } else if (!strcasecmp(param, "weight")) {
2767                 q->weight = atoi(val);
2768         } else if (!strcasecmp(param, "timeoutrestart")) {
2769                 q->timeoutrestart = ast_true(val);
2770         } else if (!strcasecmp(param, "defaultrule")) {
2771                 ast_string_field_set(q, defaultrule, val);
2772         } else if (!strcasecmp(param, "timeoutpriority")) {
2773                 if (!strcasecmp(val, "conf")) {
2774                         q->timeoutpriority = TIMEOUT_PRIORITY_CONF;
2775                 } else {
2776                         q->timeoutpriority = TIMEOUT_PRIORITY_APP;
2777                 }
2778         } else if (failunknown) {
2779                 if (linenum >= 0) {
2780                         ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
2781                                 q->name, param, linenum);
2782                 } else {
2783                         ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
2784                 }
2785         }
2786 }
2787
2788
2789 #define QUEUE_PAUSED_DEVSTATE AST_DEVICE_INUSE
2790 #define QUEUE_UNPAUSED_DEVSTATE AST_DEVICE_NOT_INUSE
2791 #define QUEUE_UNKNOWN_PAUSED_DEVSTATE AST_DEVICE_NOT_INUSE
2792
2793 /*! \internal
2794  * \brief If adding a single new member to a queue, use this function instead of ao2_linking.
2795  *        This adds round robin queue position data for a fresh member as well as links it.
2796  * \param queue Which queue the member is being added to
2797  * \param mem Which member is being added to the queue
2798  */
2799 static void member_add_to_queue(struct call_queue *queue, struct member *mem)
2800 {
2801         ao2_lock(queue->members);
2802         mem->queuepos = ao2_container_count(queue->members);
2803         ao2_link(queue->members, mem);
2804         ast_devstate_changed(mem->paused ? QUEUE_PAUSED_DEVSTATE : QUEUE_UNPAUSED_DEVSTATE,
2805                 AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", queue->name, mem->interface);
2806         ao2_unlock(queue->members);
2807 }
2808
2809 /*! \internal
2810  * \brief If removing a single member from a queue, use this function instead of ao2_unlinking.
2811  *        This will perform round robin queue position reordering for the remaining members.
2812  * \param queue Which queue the member is being removed from
2813  * \param member Which member is being removed from the queue
2814  */
2815 static void member_remove_from_queue(struct call_queue *queue, struct member *mem)
2816 {
2817         ao2_lock(queue->members);
2818         ast_devstate_changed(QUEUE_UNKNOWN_PAUSED_DEVSTATE, AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", queue->name, mem->interface);
2819         queue_member_follower_removal(queue, mem);
2820         ao2_unlink(queue->members, mem);
2821         ao2_unlock(queue->members);
2822 }
2823
2824 /*!
2825  * \brief Find rt member record to update otherwise create one.
2826  *
2827  * Search for member in queue, if found update penalty/paused state,
2828  * if no member exists create one flag it as a RT member and add to queue member list.
2829 */
2830 static void rt_handle_member_record(struct call_queue *q, char *interface, struct ast_config *member_config)
2831 {
2832         struct member *m;
2833         struct ao2_iterator mem_iter;
2834         int penalty = 0;
2835         int paused  = 0;
2836         int found = 0;
2837         int ringinuse = q->ringinuse;
2838
2839         const char *config_val;
2840         const char *rt_uniqueid = ast_variable_retrieve(member_config, interface, "uniqueid");
2841         const char *membername = S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface);
2842         const char *state_interface = S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface);
2843         const char *penalty_str = ast_variable_retrieve(member_config, interface, "penalty");
2844         const char *paused_str = ast_variable_retrieve(member_config, interface, "paused");
2845
2846         if (ast_strlen_zero(rt_uniqueid)) {
2847                 ast_log(LOG_WARNING, "Realtime field uniqueid is empty for member %s\n", S_OR(membername, "NULL"));
2848                 return;
2849         }
2850
2851         if (penalty_str) {
2852                 penalty = atoi(penalty_str);
2853                 if ((penalty < 0) && negative_penalty_invalid) {
2854                         return;
2855                 } else if (penalty < 0) {
2856                         penalty = 0;
2857                 }
2858         }
2859
2860         if (paused_str) {
2861                 paused = atoi(paused_str);
2862                 if (paused < 0) {
2863                         paused = 0;
2864                 }
2865         }
2866
2867         if ((config_val = ast_variable_retrieve(member_config, interface, realtime_ringinuse_field))) {
2868                 if (ast_true(config_val)) {
2869                         ringinuse = 1;
2870                 } else if (ast_false(config_val)) {
2871                         ringinuse = 0;
2872                 } else {
2873                         ast_log(LOG_WARNING, "Invalid value of '%s' field for %s in queue '%s'\n", realtime_ringinuse_field, interface, q->name);
2874                 }
2875         }
2876
2877         /* Find member by realtime uniqueid and update */
2878         mem_iter = ao2_iterator_init(q->members, 0);
2879         while ((m = ao2_iterator_next(&mem_iter))) {
2880                 if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) {
2881                         m->dead = 0;    /* Do not delete this one. */
2882                         ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
2883                         if (paused_str) {
2884                                 m->paused = paused;
2885                                 ast_devstate_changed(m->paused ? QUEUE_PAUSED_DEVSTATE : QUEUE_UNPAUSED_DEVSTATE,
2886                                         AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", q->name, m->interface);
2887                         }
2888                         if (strcasecmp(state_interface, m->state_interface)) {
2889                                 ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
2890                         }
2891                         m->penalty = penalty;
2892                         m->ringinuse = ringinuse;
2893                         found = 1;
2894                         ao2_ref(m, -1);
2895                         break;
2896                 }
2897                 ao2_ref(m, -1);
2898         }
2899         ao2_iterator_destroy(&mem_iter);
2900
2901         /* Create a new member */
2902         if (!found) {
2903                 if ((m = create_queue_member(interface, membername, penalty, paused, state_interface, ringinuse))) {
2904                         m->dead = 0;
2905                         m->realtime = 1;
2906                         ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
2907                         if (!log_membername_as_agent) {
2908                                 ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
2909                         } else {
2910                                 ast_queue_log(q->name, "REALTIME", m->membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
2911                         }
2912                         member_add_to_queue(q, m);
2913                         ao2_ref(m, -1);
2914                         m = NULL;
2915                 }
2916         }
2917 }
2918
2919 /*! \brief Iterate through queue's member list and delete them */
2920 static void free_members(struct call_queue *q, int all)
2921 {
2922         /* Free non-dynamic members */
2923         struct member *cur;
2924         struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
2925
2926         while ((cur = ao2_iterator_next(&mem_iter))) {
2927                 if (all || !cur->dynamic) {
2928                         member_remove_from_queue(q, cur);
2929                 }
2930                 ao2_ref(cur, -1);
2931         }
2932         ao2_iterator_destroy(&mem_iter);
2933 }
2934
2935 /*! \brief Free queue's member list then its string fields */
2936 static void destroy_queue(void *obj)
2937 {
2938         struct call_queue *q = obj;
2939         int i;
2940
2941         free_members(q, 1);
2942         ast_string_field_free_memory(q);
2943         for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
2944                 if (q->sound_periodicannounce[i]) {
2945                         free(q->sound_periodicannounce[i]);
2946                 }
2947         }
2948         ao2_ref(q->members, -1);
2949 }
2950
2951 static struct call_queue *alloc_queue(const char *queuename)
2952 {
2953         struct call_queue *q;
2954
2955         if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) {
2956                 if (ast_string_field_init(q, 64)) {
2957                         queue_t_unref(q, "String field allocation failed");
2958                         return NULL;
2959                 }
2960                 ast_string_field_set(q, name, queuename);
2961         }
2962         return q;
2963 }
2964
2965 /*!
2966  * \brief Reload a single queue via realtime.
2967  *
2968  * Check for statically defined queue first, check if deleted RT queue,
2969  * check for new RT queue, if queue vars are not defined init them with defaults.
2970  * reload RT queue vars, set RT queue members dead and reload them, return finished queue.
2971  * \retval the queue,
2972  * \retval NULL if it doesn't exist.
2973  * \note Should be called with the "queues" container locked.
2974 */
2975 static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
2976 {
2977         struct ast_variable *v;
2978         struct call_queue *q, tmpq = {
2979                 .name = queuename,
2980         };
2981         struct member *m;
2982         struct ao2_iterator mem_iter;
2983         char *interface = NULL;
2984         const char *tmp_name;
2985         char *tmp;
2986         char tmpbuf[64];        /* Must be longer than the longest queue param name. */
2987
2988         /* Static queues override realtime. */
2989         if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Check if static queue exists"))) {
2990                 ao2_lock(q);
2991                 if (!q->realtime) {
2992                         if (q->dead) {
2993                                 ao2_unlock(q);
2994                                 queue_t_unref(q, "Queue is dead; can't return it");
2995                                 return NULL;
2996                         }
2997                         ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
2998                         ao2_unlock(q);
2999                         return q;
3000                 }
3001         } else if (!member_config) {
3002                 /* Not found in the list, and it's not realtime ... */
3003                 return NULL;
3004         }
3005         /* Check if queue is defined in realtime. */
3006         if (!queue_vars) {
3007                 /* Delete queue from in-core list if it has been deleted in realtime. */
3008                 if (q) {
3009                         /*! \note Hmm, can't seem to distinguish a DB failure from a not
3010                            found condition... So we might delete an in-core queue
3011                            in case of DB failure. */
3012                         ast_debug(1, "Queue %s not found in realtime.\n", queuename);
3013
3014                         q->dead = 1;
3015                         /* Delete if unused (else will be deleted when last caller leaves). */
3016                         queues_t_unlink(queues, q, "Unused; removing from container");
3017                         ao2_unlock(q);
3018                         queue_t_unref(q, "Queue is dead; can't return it");
3019                 }
3020                 return NULL;
3021         }
3022
3023         /* Create a new queue if an in-core entry does not exist yet. */
3024         if (!q) {
3025                 struct ast_variable *tmpvar = NULL;
3026                 if (!(q = alloc_queue(queuename))) {
3027                         return NULL;
3028                 }
3029                 ao2_lock(q);
3030                 clear_queue(q);
3031                 q->realtime = 1;
3032                 /*Before we initialize the queue, we need to set the strategy, so that linear strategy
3033                  * will allocate the members properly
3034                  */
3035                 for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) {
3036                         if (!strcasecmp(tmpvar->name, "strategy")) {
3037                                 q->strategy = strat2int(tmpvar->value);
3038                                 if (q->strategy < 0) {
3039                                         ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
3040                                         tmpvar->value, q->name);
3041                                         q->strategy = QUEUE_STRATEGY_RINGALL;
3042                                 }
3043                                 break;
3044                         }
3045                 }
3046                 /* We traversed all variables and didn't find a strategy */
3047                 if (!tmpvar) {
3048                         q->strategy = QUEUE_STRATEGY_RINGALL;
3049                 }
3050                 queues_t_link(queues, q, "Add queue to container");
3051         }
3052         init_queue(q);          /* Ensure defaults for all parameters not set explicitly. */
3053
3054         memset(tmpbuf, 0, sizeof(tmpbuf));
3055         for (v = queue_vars; v; v = v->next) {
3056                 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
3057                 if (strchr(v->name, '_')) {
3058                         ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
3059                         tmp_name = tmpbuf;
3060                         tmp = tmpbuf;
3061                         while ((tmp = strchr(tmp, '_'))) {
3062                                 *tmp++ = '-';
3063                         }
3064                 } else {
3065                         tmp_name = v->name;
3066                 }
3067
3068                 /* NULL values don't get returned from realtime; blank values should
3069                  * still get set.  If someone doesn't want a value to be set, they
3070                  * should set the realtime column to NULL, not blank. */
3071                 queue_set_param(q, tmp_name, v->value, -1, 0);
3072         }
3073
3074         /* Temporarily set realtime members dead so we can detect deleted ones. */
3075         mem_iter = ao2_iterator_init(q->members, 0);
3076         while ((m = ao2_iterator_next(&mem_iter))) {
3077                 if (m->realtime) {
3078                         m->dead = 1;
3079                 }
3080                 ao2_ref(m, -1);
3081         }
3082         ao2_iterator_destroy(&mem_iter);
3083
3084         while ((interface = ast_category_browse(member_config, interface))) {
3085                 rt_handle_member_record(q, interface, member_config);
3086         }
3087
3088         /* Delete all realtime members that have been deleted in DB. */
3089         mem_iter = ao2_iterator_init(q->members, 0);
3090         while ((m = ao2_iterator_next(&mem_iter))) {
3091                 if (m->dead) {
3092                         if (ast_strlen_zero(m->membername) || !log_membername_as_agent) {
3093                                 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
3094                         } else {
3095                                 ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
3096                         }
3097                         member_remove_from_queue(q, m);
3098                 }
3099                 ao2_ref(m, -1);
3100         }
3101         ao2_iterator_destroy(&mem_iter);
3102
3103         ao2_unlock(q);
3104
3105         return q;
3106 }
3107
3108 /*!
3109  * note  */
3110
3111 /*!
3112  * \internal
3113  * \brief Returns reference to the named queue. If the queue is realtime, it will load the queue as well.
3114  * \param queuename - name of the desired queue
3115  *
3116  * \retval the queue
3117  * \retval NULL if it doesn't exist
3118  */
3119 static struct call_queue *find_load_queue_rt_friendly(const char *queuename)
3120 {
3121         struct ast_variable *queue_vars;
3122         struct ast_config *member_config = NULL;
3123         struct call_queue *q = NULL, tmpq = {
3124                 .name = queuename,
3125         };
3126         int prev_weight = 0;
3127
3128         /* Find the queue in the in-core list first. */
3129         q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Look for queue in memory first");
3130
3131         if (!q || q->realtime) {
3132                 /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all
3133                    queue operations while waiting for the DB.
3134
3135                    This will be two separate database transactions, so we might
3136                    see queue parameters as they were before another process
3137                    changed the queue and member list as it was after the change.
3138                    Thus we might see an empty member list when a queue is
3139                    deleted. In practise, this is unlikely to cause a problem. */
3140
3141                 queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL);
3142                 if (queue_vars) {
3143                         member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL);
3144                         if (!member_config) {
3145                                 ast_debug(1, "No queue_members defined in config extconfig.conf\n");
3146                                 member_config = ast_config_new();
3147                         }
3148                 }
3149                 if (q) {
3150                         prev_weight = q->weight ? 1 : 0;
3151                         queue_t_unref(q, "Need to find realtime queue");
3152                 }
3153
3154                 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
3155                 ast_config_destroy(member_config);
3156                 ast_variables_destroy(queue_vars);
3157
3158                 /* update the use_weight value if the queue's has gained or lost a weight */
3159                 if (q) {
3160                         if (!q->weight && prev_weight) {
3161                                 ast_atomic_fetchadd_int(&use_weight, -1);
3162                         }
3163                         if (q->weight && !prev_weight) {
3164                                 ast_atomic_fetchadd_int(&use_weight, +1);
3165                         }
3166                 }
3167                 /* Other cases will end up with the proper value for use_weight */
3168         } else {
3169                 update_realtime_members(q);
3170         }
3171         return q;
3172 }
3173
3174 static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
3175 {
3176         int ret = -1;
3177
3178         if (ast_strlen_zero(mem->rt_uniqueid)) {
3179                 return ret;
3180         }
3181
3182         if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) > 0) {
3183                 ret = 0;
3184         }
3185
3186         return ret;
3187 }
3188
3189
3190 static void update_realtime_members(struct call_queue *q)
3191 {
3192         struct ast_config *member_config = NULL;
3193         struct member *m;
3194         char *interface = NULL;
3195         struct ao2_iterator mem_iter;
3196
3197         if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , SENTINEL))) {
3198                 /* This queue doesn't have realtime members. If the queue still has any realtime
3199                  * members in memory, they need to be removed.
3200                  */
3201                 ao2_lock(q);
3202                 mem_iter = ao2_iterator_init(q->members, 0);
3203                 while ((m = ao2_iterator_next(&mem_iter))) {
3204                         if (m->realtime) {
3205                                 member_remove_from_queue(q, m);
3206                         }
3207                         ao2_ref(m, -1);
3208                 }
3209                 ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name);
3210                 ao2_unlock(q);
3211                 return;
3212         }
3213
3214         ao2_lock(q);
3215
3216         /* Temporarily set realtime  members dead so we can detect deleted ones.*/
3217         mem_iter = ao2_iterator_init(q->members, 0);
3218         while ((m = ao2_iterator_next(&mem_iter))) {
3219                 if (m->realtime) {
3220                         m->dead = 1;
3221                 }
3222                 ao2_ref(m, -1);
3223         }
3224         ao2_iterator_destroy(&mem_iter);
3225
3226         while ((interface = ast_category_browse(member_config, interface))) {
3227                 rt_handle_member_record(q, interface, member_config);
3228         }
3229
3230         /* Delete all realtime members that have been deleted in DB. */
3231         mem_iter = ao2_iterator_init(q->members, 0);
3232         while ((m = ao2_iterator_next(&mem_iter))) {
3233                 if (m->dead) {
3234                         if (ast_strlen_zero(m->membername) || !log_membername_as_agent) {
3235                                 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
3236                         } else {
3237                                 ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
3238                         }
3239                         member_remove_from_queue(q, m);
3240                 }
3241                 ao2_ref(m, -1);
3242         }
3243         ao2_iterator_destroy(&mem_iter);
3244         ao2_unlock(q);
3245         ast_config_destroy(member_config);
3246 }
3247
3248 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
3249 {
3250         struct call_queue *q;
3251         struct queue_ent *cur, *prev = NULL;
3252         int res = -1;
3253         int pos = 0;
3254         int inserted = 0;
3255
3256         if (!(q = find_load_queue_rt_friendly(queuename))) {
3257                 return res;
3258         }
3259         ao2_lock(q);
3260
3261         /* This is our one */
3262         if (q->joinempty) {
3263                 int status = 0;
3264                 if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, q->joinempty))) {
3265                         *reason = QUEUE_JOINEMPTY;
3266                         ao2_unlock(q);
3267                         queue_t_unref(q, "Done with realtime queue");
3268                         return res;