Asterisk - The Open Source Telephony Project  18.5.0
app_queue.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2018, Digium, Inc.
5  *
6  * Mark Spencer <[email protected]>
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 <[email protected]>
24  *
25  * \par Development notes
26  * \note 2004-11-25: Persistent Dynamic Members added by:
27  * NetNation Communications (www.netnation.com)
28  * Kevin Lindsay <[email protected]>
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 <[email protected]>:
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 <[email protected]>
49  * Added Priority jumping code for adding and removing queue members by Jonathan Stanton <[email protected]>
50  *
51  * Fixed to work with CVS as of 2004-02-25 and released as 1.07a
52  * by Matthew Enger <[email protected]>
53  *
54  * \ingroup applications
55  */
56 
57 /*! \li \ref app_queues.c uses configuration file \ref queues.conf
58  * \addtogroup configuration_file
59  */
60 
61 /*! \page queues.conf queues.conf
62  * \verbinclude queues.conf.sample
63  */
64 
65 /*** MODULEINFO
66  <use type="module">res_monitor</use>
67  <support_level>core</support_level>
68  ***/
69 
70 #include "asterisk.h"
71 
72 #include <sys/time.h>
73 #include <signal.h>
74 #include <netinet/in.h>
75 #include <ctype.h>
76 
77 #include "asterisk/lock.h"
78 #include "asterisk/file.h"
79 #include "asterisk/channel.h"
80 #include "asterisk/pbx.h"
81 #include "asterisk/app.h"
82 #include "asterisk/linkedlists.h"
83 #include "asterisk/module.h"
84 #include "asterisk/translate.h"
85 #include "asterisk/say.h"
86 #include "asterisk/features.h"
87 #include "asterisk/musiconhold.h"
88 #include "asterisk/cli.h"
89 #include "asterisk/manager.h"
90 #include "asterisk/config.h"
91 #include "asterisk/monitor.h"
92 #include "asterisk/utils.h"
93 #include "asterisk/causes.h"
94 #include "asterisk/astdb.h"
95 #include "asterisk/devicestate.h"
96 #include "asterisk/stringfields.h"
97 #include "asterisk/astobj2.h"
98 #include "asterisk/strings.h"
99 #include "asterisk/taskprocessor.h"
100 #include "asterisk/aoc.h"
101 #include "asterisk/callerid.h"
102 #include "asterisk/term.h"
103 #include "asterisk/dial.h"
106 #include "asterisk/bridge_after.h"
107 #include "asterisk/stasis_bridges.h"
108 #include "asterisk/core_local.h"
109 #include "asterisk/mixmonitor.h"
110 #include "asterisk/bridge_basic.h"
111 #include "asterisk/max_forwards.h"
112 
113 /*!
114  * \par Please read before modifying this file.
115  * There are three locks which are regularly used
116  * throughout this file, the queue list lock, the lock
117  * for each individual queue, and the interface list lock.
118  * Please be extra careful to always lock in the following order
119  * 1) queue list lock
120  * 2) individual queue lock
121  * 3) interface list lock
122  * This order has sort of "evolved" over the lifetime of this
123  * application, but it is now in place this way, so please adhere
124  * to this order!
125  */
126 
127 /*** DOCUMENTATION
128  <application name="Queue" language="en_US">
129  <synopsis>
130  Queue a call for a call queue.
131  </synopsis>
132  <syntax>
133  <parameter name="queuename" required="true" />
134  <parameter name="options">
135  <optionlist>
136  <option name="b" argsep="^">
137  <para>Before initiating an outgoing call, <literal>Gosub</literal> to the specified
138  location using the newly created channel. The <literal>Gosub</literal> will be
139  executed for each destination channel.</para>
140  <argument name="context" required="false" />
141  <argument name="exten" required="false" />
142  <argument name="priority" required="true" hasparams="optional" argsep="^">
143  <argument name="arg1" multiple="true" required="true" />
144  <argument name="argN" />
145  </argument>
146  </option>
147  <option name="B" argsep="^">
148  <para>Before initiating the outgoing call(s), <literal>Gosub</literal> to the
149  specified location using the current channel.</para>
150  <argument name="context" required="false" />
151  <argument name="exten" required="false" />
152  <argument name="priority" required="true" hasparams="optional" argsep="^">
153  <argument name="arg1" multiple="true" required="true" />
154  <argument name="argN" />
155  </argument>
156  </option>
157  <option name="C">
158  <para>Mark all calls as "answered elsewhere" when cancelled.</para>
159  </option>
160  <option name="c">
161  <para>Continue in the dialplan if the callee hangs up.</para>
162  </option>
163  <option name="d">
164  <para>data-quality (modem) call (minimum delay).</para>
165  </option>
166  <option name="F" argsep="^">
167  <argument name="context" required="false" />
168  <argument name="exten" required="false" />
169  <argument name="priority" required="true" />
170  <para>When the caller hangs up, transfer the <emphasis>called member</emphasis>
171  to the specified destination and <emphasis>start</emphasis> execution at that location.</para>
172  <para>NOTE: Any channel variables you want the called channel to inherit from the caller channel must be
173  prefixed with one or two underbars ('_').</para>
174  </option>
175  <option name="F">
176  <para>When the caller hangs up, transfer the <emphasis>called member</emphasis> to the next priority of
177  the current extension and <emphasis>start</emphasis> execution at that location.</para>
178  <para>NOTE: Any channel variables you want the called channel to inherit from the caller channel must be
179  prefixed with one or two underbars ('_').</para>
180  <para>NOTE: Using this option from a Macro() or GoSub() might not make sense as there would be no return points.</para>
181  </option>
182  <option name="h">
183  <para>Allow <emphasis>callee</emphasis> to hang up by pressing <literal>*</literal>.</para>
184  </option>
185  <option name="H">
186  <para>Allow <emphasis>caller</emphasis> to hang up by pressing <literal>*</literal>.</para>
187  </option>
188  <option name="n">
189  <para>No retries on the timeout; will exit this application and
190  go to the next step.</para>
191  </option>
192  <option name="i">
193  <para>Ignore call forward requests from queue members and do nothing
194  when they are requested.</para>
195  </option>
196  <option name="I">
197  <para>Asterisk will ignore any connected line update requests or any redirecting party
198  update requests it may receive on this dial attempt.</para>
199  </option>
200  <option name="r">
201  <para>Ring instead of playing MOH. Periodic Announcements are still made, if applicable.</para>
202  </option>
203  <option name="R">
204  <para>Ring instead of playing MOH when a member channel is actually ringing.</para>
205  </option>
206  <option name="t">
207  <para>Allow the <emphasis>called</emphasis> user to transfer the calling user.</para>
208  </option>
209  <option name="T">
210  <para>Allow the <emphasis>calling</emphasis> user to transfer the call.</para>
211  </option>
212  <option name="w">
213  <para>Allow the <emphasis>called</emphasis> user to write the conversation to
214  disk via Monitor.</para>
215  </option>
216  <option name="W">
217  <para>Allow the <emphasis>calling</emphasis> user to write the conversation to
218  disk via Monitor.</para>
219  </option>
220  <option name="k">
221  <para>Allow the <emphasis>called</emphasis> party to enable parking of the call by sending
222  the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
223  </option>
224  <option name="K">
225  <para>Allow the <emphasis>calling</emphasis> party to enable parking of the call by sending
226  the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
227  </option>
228  <option name="x">
229  <para>Allow the <emphasis>called</emphasis> user to write the conversation
230  to disk via MixMonitor.</para>
231  </option>
232  <option name="X">
233  <para>Allow the <emphasis>calling</emphasis> user to write the conversation to
234  disk via MixMonitor.</para>
235  </option>
236  </optionlist>
237  </parameter>
238  <parameter name="URL">
239  <para><replaceable>URL</replaceable> will be sent to the called party if the channel supports it.</para>
240  </parameter>
241  <parameter name="announceoverride" />
242  <parameter name="timeout">
243  <para>Will cause the queue to fail out after a specified number of
244  seconds, checked between each <filename>queues.conf</filename> <replaceable>timeout</replaceable> and
245  <replaceable>retry</replaceable> cycle.</para>
246  </parameter>
247  <parameter name="AGI">
248  <para>Will setup an AGI script to be executed on the calling party's channel once they are
249  connected to a queue member.</para>
250  </parameter>
251  <parameter name="macro">
252  <para>Will run a macro on the called party's channel (the queue member) once the parties are connected.</para>
253  <para>NOTE: Macros are deprecated, GoSub should be used instead.</para>
254  </parameter>
255  <parameter name="gosub">
256  <para>Will run a gosub on the called party's channel (the queue member)
257  once the parties are connected. The subroutine execution starts in the
258  named context at the s exten and priority 1.</para>
259  </parameter>
260  <parameter name="rule">
261  <para>Will cause the queue's defaultrule to be overridden by the rule specified.</para>
262  </parameter>
263  <parameter name="position">
264  <para>Attempt to enter the caller into the queue at the numerical position specified. <literal>1</literal>
265  would attempt to enter the caller at the head of the queue, and <literal>3</literal> would attempt to place
266  the caller third in the queue.</para>
267  </parameter>
268  </syntax>
269  <description>
270  <para>In addition to transferring the call, a call may be parked and then picked
271  up by another user.</para>
272  <para>This application will return to the dialplan if the queue does not exist, or
273  any of the join options cause the caller to not enter the queue.</para>
274  <para>This application does not automatically answer and should be preceeded
275  by an application such as Answer(), Progress(), or Ringing().</para>
276  <para>This application sets the following channel variables upon completion:</para>
277  <variablelist>
278  <variable name="QUEUESTATUS">
279  <para>The status of the call as a text string.</para>
280  <value name="TIMEOUT" />
281  <value name="FULL" />
282  <value name="JOINEMPTY" />
283  <value name="LEAVEEMPTY" />
284  <value name="JOINUNAVAIL" />
285  <value name="LEAVEUNAVAIL" />
286  <value name="CONTINUE" />
287  </variable>
288  <variable name="ABANDONED">
289  <para>If the call was not answered by an agent this variable will be TRUE.</para>
290  <value name="TRUE" />
291  </variable>
292  </variablelist>
293  </description>
294  <see-also>
295  <ref type="application">Queue</ref>
296  <ref type="application">QueueLog</ref>
297  <ref type="application">AddQueueMember</ref>
298  <ref type="application">RemoveQueueMember</ref>
299  <ref type="application">PauseQueueMember</ref>
300  <ref type="application">UnpauseQueueMember</ref>
301  <ref type="function">QUEUE_VARIABLES</ref>
302  <ref type="function">QUEUE_MEMBER</ref>
303  <ref type="function">QUEUE_MEMBER_COUNT</ref>
304  <ref type="function">QUEUE_EXISTS</ref>
305  <ref type="function">QUEUE_GET_CHANNEL</ref>
306  <ref type="function">QUEUE_WAITING_COUNT</ref>
307  <ref type="function">QUEUE_MEMBER_LIST</ref>
308  <ref type="function">QUEUE_MEMBER_PENALTY</ref>
309  </see-also>
310  </application>
311  <application name="AddQueueMember" language="en_US">
312  <synopsis>
313  Dynamically adds queue members.
314  </synopsis>
315  <syntax>
316  <parameter name="queuename" required="true" />
317  <parameter name="interface" />
318  <parameter name="penalty" />
319  <parameter name="options" />
320  <parameter name="membername" />
321  <parameter name="stateinterface" />
322  <parameter name="wrapuptime" />
323  </syntax>
324  <description>
325  <para>Dynamically adds interface to an existing queue. If the interface is
326  already in the queue it will return an error.</para>
327  <para>This application sets the following channel variable upon completion:</para>
328  <variablelist>
329  <variable name="AQMSTATUS">
330  <para>The status of the attempt to add a queue member as a text string.</para>
331  <value name="ADDED" />
332  <value name="MEMBERALREADY" />
333  <value name="NOSUCHQUEUE" />
334  </variable>
335  </variablelist>
336  </description>
337  <see-also>
338  <ref type="application">Queue</ref>
339  <ref type="application">QueueLog</ref>
340  <ref type="application">AddQueueMember</ref>
341  <ref type="application">RemoveQueueMember</ref>
342  <ref type="application">PauseQueueMember</ref>
343  <ref type="application">UnpauseQueueMember</ref>
344  <ref type="function">QUEUE_VARIABLES</ref>
345  <ref type="function">QUEUE_MEMBER</ref>
346  <ref type="function">QUEUE_MEMBER_COUNT</ref>
347  <ref type="function">QUEUE_EXISTS</ref>
348  <ref type="function">QUEUE_GET_CHANNEL</ref>
349  <ref type="function">QUEUE_WAITING_COUNT</ref>
350  <ref type="function">QUEUE_MEMBER_LIST</ref>
351  <ref type="function">QUEUE_MEMBER_PENALTY</ref>
352  </see-also>
353  </application>
354  <application name="RemoveQueueMember" language="en_US">
355  <synopsis>
356  Dynamically removes queue members.
357  </synopsis>
358  <syntax>
359  <parameter name="queuename" required="true" />
360  <parameter name="interface" />
361  </syntax>
362  <description>
363  <para>If the interface is <emphasis>NOT</emphasis> in the queue it will return an error.</para>
364  <para>This application sets the following channel variable upon completion:</para>
365  <variablelist>
366  <variable name="RQMSTATUS">
367  <value name="REMOVED" />
368  <value name="NOTINQUEUE" />
369  <value name="NOSUCHQUEUE" />
370  <value name="NOTDYNAMIC" />
371  </variable>
372  </variablelist>
373  <para>Example: RemoveQueueMember(techsupport,SIP/3000)</para>
374  </description>
375  <see-also>
376  <ref type="application">Queue</ref>
377  <ref type="application">QueueLog</ref>
378  <ref type="application">AddQueueMember</ref>
379  <ref type="application">RemoveQueueMember</ref>
380  <ref type="application">PauseQueueMember</ref>
381  <ref type="application">UnpauseQueueMember</ref>
382  <ref type="function">QUEUE_VARIABLES</ref>
383  <ref type="function">QUEUE_MEMBER</ref>
384  <ref type="function">QUEUE_MEMBER_COUNT</ref>
385  <ref type="function">QUEUE_EXISTS</ref>
386  <ref type="function">QUEUE_GET_CHANNEL</ref>
387  <ref type="function">QUEUE_WAITING_COUNT</ref>
388  <ref type="function">QUEUE_MEMBER_LIST</ref>
389  <ref type="function">QUEUE_MEMBER_PENALTY</ref>
390  </see-also>
391  </application>
392  <application name="PauseQueueMember" language="en_US">
393  <synopsis>
394  Pauses a queue member.
395  </synopsis>
396  <syntax>
397  <parameter name="queuename" />
398  <parameter name="interface" required="true" />
399  <parameter name="options" />
400  <parameter name="reason">
401  <para>Is used to add extra information to the appropriate queue_log entries and manager events.</para>
402  </parameter>
403  </syntax>
404  <description>
405  <para>Pauses (blocks calls for) a queue member. The given interface will be paused in the given queue.
406  This prevents any calls from being sent from the queue to the interface until it is
407  unpaused with UnpauseQueueMember or the manager interface. If no queuename is given,
408  the interface is paused in every queue it is a member of. The application will fail if the
409  interface is not found.</para>
410  <para>This application sets the following channel variable upon completion:</para>
411  <variablelist>
412  <variable name="PQMSTATUS">
413  <para>The status of the attempt to pause a queue member as a text string.</para>
414  <value name="PAUSED" />
415  <value name="NOTFOUND" />
416  </variable>
417  </variablelist>
418  <para>Example: PauseQueueMember(,SIP/3000)</para>
419  </description>
420  <see-also>
421  <ref type="application">Queue</ref>
422  <ref type="application">QueueLog</ref>
423  <ref type="application">AddQueueMember</ref>
424  <ref type="application">RemoveQueueMember</ref>
425  <ref type="application">PauseQueueMember</ref>
426  <ref type="application">UnpauseQueueMember</ref>
427  <ref type="function">QUEUE_VARIABLES</ref>
428  <ref type="function">QUEUE_MEMBER</ref>
429  <ref type="function">QUEUE_MEMBER_COUNT</ref>
430  <ref type="function">QUEUE_EXISTS</ref>
431  <ref type="function">QUEUE_GET_CHANNEL</ref>
432  <ref type="function">QUEUE_WAITING_COUNT</ref>
433  <ref type="function">QUEUE_MEMBER_LIST</ref>
434  <ref type="function">QUEUE_MEMBER_PENALTY</ref>
435  </see-also>
436  </application>
437  <application name="UnpauseQueueMember" language="en_US">
438  <synopsis>
439  Unpauses a queue member.
440  </synopsis>
441  <syntax>
442  <parameter name="queuename" />
443  <parameter name="interface" required="true" />
444  <parameter name="options" />
445  <parameter name="reason">
446  <para>Is used to add extra information to the appropriate queue_log entries and manager events.</para>
447  </parameter>
448  </syntax>
449  <description>
450  <para>Unpauses (resumes calls to) a queue member. This is the counterpart to <literal>PauseQueueMember()</literal>
451  and operates exactly the same way, except it unpauses instead of pausing the given interface.</para>
452  <para>This application sets the following channel variable upon completion:</para>
453  <variablelist>
454  <variable name="UPQMSTATUS">
455  <para>The status of the attempt to unpause a queue member as a text string.</para>
456  <value name="UNPAUSED" />
457  <value name="NOTFOUND" />
458  </variable>
459  </variablelist>
460  <para>Example: UnpauseQueueMember(,SIP/3000)</para>
461  </description>
462  <see-also>
463  <ref type="application">Queue</ref>
464  <ref type="application">QueueLog</ref>
465  <ref type="application">AddQueueMember</ref>
466  <ref type="application">RemoveQueueMember</ref>
467  <ref type="application">PauseQueueMember</ref>
468  <ref type="application">UnpauseQueueMember</ref>
469  <ref type="function">QUEUE_VARIABLES</ref>
470  <ref type="function">QUEUE_MEMBER</ref>
471  <ref type="function">QUEUE_MEMBER_COUNT</ref>
472  <ref type="function">QUEUE_EXISTS</ref>
473  <ref type="function">QUEUE_GET_CHANNEL</ref>
474  <ref type="function">QUEUE_WAITING_COUNT</ref>
475  <ref type="function">QUEUE_MEMBER_LIST</ref>
476  <ref type="function">QUEUE_MEMBER_PENALTY</ref>
477  </see-also>
478  </application>
479  <application name="QueueLog" language="en_US">
480  <synopsis>
481  Writes to the queue_log file.
482  </synopsis>
483  <syntax>
484  <parameter name="queuename" required="true" />
485  <parameter name="uniqueid" required="true" />
486  <parameter name="agent" required="true" />
487  <parameter name="event" required="true" />
488  <parameter name="additionalinfo" />
489  </syntax>
490  <description>
491  <para>Allows you to write your own events into the queue log.</para>
492  <para>Example: QueueLog(101,${UNIQUEID},${AGENT},WENTONBREAK,600)</para>
493  </description>
494  <see-also>
495  <ref type="application">Queue</ref>
496  <ref type="application">QueueLog</ref>
497  <ref type="application">AddQueueMember</ref>
498  <ref type="application">RemoveQueueMember</ref>
499  <ref type="application">PauseQueueMember</ref>
500  <ref type="application">UnpauseQueueMember</ref>
501  <ref type="function">QUEUE_VARIABLES</ref>
502  <ref type="function">QUEUE_MEMBER</ref>
503  <ref type="function">QUEUE_MEMBER_COUNT</ref>
504  <ref type="function">QUEUE_EXISTS</ref>
505  <ref type="function">QUEUE_GET_CHANNEL</ref>
506  <ref type="function">QUEUE_WAITING_COUNT</ref>
507  <ref type="function">QUEUE_MEMBER_LIST</ref>
508  <ref type="function">QUEUE_MEMBER_PENALTY</ref>
509  </see-also>
510  </application>
511  <application name="QueueUpdate" language="en_US">
512  <synopsis>
513  Writes to the queue_log file for OutBound calls and updates Realtime Data.
514  Is used at h extension to be able to have all the parameters.
515  </synopsis>
516  <syntax>
517  <parameter name="queuename" required="true" />
518  <parameter name="uniqueid" required="true" />
519  <parameter name="agent" required="true" />
520  <parameter name="status" required="true" />
521  <parameter name="talktime" required="true" />
522  <parameter name="params" required="false" />
523  </syntax>
524  <description>
525  <para>Allows you to write Outbound events into the queue log.</para>
526  <para>Example: exten => h,1,QueueUpdate(${QUEUE}, ${UNIQUEID}, ${AGENT}, ${DIALSTATUS}, ${ANSWEREDTIME}, ${DIALEDTIME} | ${DIALEDNUMBER})</para>
527  </description>
528  </application>
529  <function name="QUEUE_VARIABLES" language="en_US">
530  <synopsis>
531  Return Queue information in variables.
532  </synopsis>
533  <syntax>
534  <parameter name="queuename" required="true">
535  <enumlist>
536  <enum name="QUEUEMAX">
537  <para>Maxmimum number of calls allowed.</para>
538  </enum>
539  <enum name="QUEUESTRATEGY">
540  <para>The strategy of the queue.</para>
541  </enum>
542  <enum name="QUEUECALLS">
543  <para>Number of calls currently in the queue.</para>
544  </enum>
545  <enum name="QUEUEHOLDTIME">
546  <para>Current average hold time.</para>
547  </enum>
548  <enum name="QUEUECOMPLETED">
549  <para>Number of completed calls for the queue.</para>
550  </enum>
551  <enum name="QUEUEABANDONED">
552  <para>Number of abandoned calls.</para>
553  </enum>
554  <enum name="QUEUESRVLEVEL">
555  <para>Queue service level.</para>
556  </enum>
557  <enum name="QUEUESRVLEVELPERF">
558  <para>Current service level performance.</para>
559  </enum>
560  </enumlist>
561  </parameter>
562  </syntax>
563  <description>
564  <para>Makes the following queue variables available.</para>
565  <para>Returns <literal>0</literal> if queue is found and setqueuevar is defined, <literal>-1</literal> otherwise.</para>
566  </description>
567  <see-also>
568  <ref type="application">Queue</ref>
569  <ref type="application">QueueLog</ref>
570  <ref type="application">AddQueueMember</ref>
571  <ref type="application">RemoveQueueMember</ref>
572  <ref type="application">PauseQueueMember</ref>
573  <ref type="application">UnpauseQueueMember</ref>
574  <ref type="function">QUEUE_VARIABLES</ref>
575  <ref type="function">QUEUE_MEMBER</ref>
576  <ref type="function">QUEUE_MEMBER_COUNT</ref>
577  <ref type="function">QUEUE_EXISTS</ref>
578  <ref type="function">QUEUE_GET_CHANNEL</ref>
579  <ref type="function">QUEUE_WAITING_COUNT</ref>
580  <ref type="function">QUEUE_MEMBER_LIST</ref>
581  <ref type="function">QUEUE_MEMBER_PENALTY</ref>
582  </see-also>
583  </function>
584  <function name="QUEUE_MEMBER" language="en_US">
585  <synopsis>
586  Provides a count of queue members based on the provided criteria, or updates a
587  queue member's settings.
588  </synopsis>
589  <syntax>
590  <parameter name="queuename" required="false" />
591  <parameter name="option" required="true">
592  <enumlist>
593  <enum name="logged">
594  <para>Returns the number of logged-in members for the specified queue.</para>
595  </enum>
596  <enum name="free">
597  <para>Returns the number of logged-in members for the specified queue that either can take calls or are currently wrapping up after a previous call.</para>
598  </enum>
599  <enum name="ready">
600  <para>Returns the number of logged-in members for the specified queue that are immediately available to answer a call.</para>
601  </enum>
602  <enum name="count">
603  <para>Returns the total number of members for the specified queue.</para>
604  </enum>
605  <enum name="penalty">
606  <para>Gets or sets queue member penalty. If
607  <replaceable>queuename</replaceable> is not specified
608  when setting the penalty then the penalty is set in all queues
609  the interface is a member.</para>
610  </enum>
611  <enum name="paused">
612  <para>Gets or sets queue member paused status. If
613  <replaceable>queuename</replaceable> is not specified
614  when setting the paused status then the paused status is set
615  in all queues the interface is a member.</para>
616  </enum>
617  <enum name="ringinuse">
618  <para>Gets or sets queue member ringinuse. If
619  <replaceable>queuename</replaceable> is not specified
620  when setting ringinuse then ringinuse is set
621  in all queues the interface is a member.</para>
622  </enum>
623  </enumlist>
624  </parameter>
625  <parameter name="interface" required="false" />
626  </syntax>
627  <description>
628  <para>Allows access to queue counts [R] and member information [R/W].</para>
629  <para><replaceable>queuename</replaceable> is required for all read operations.</para>
630  <para><replaceable>interface</replaceable> is required for all member operations.</para>
631  </description>
632  <see-also>
633  <ref type="application">Queue</ref>
634  <ref type="application">QueueLog</ref>
635  <ref type="application">AddQueueMember</ref>
636  <ref type="application">RemoveQueueMember</ref>
637  <ref type="application">PauseQueueMember</ref>
638  <ref type="application">UnpauseQueueMember</ref>
639  <ref type="function">QUEUE_VARIABLES</ref>
640  <ref type="function">QUEUE_MEMBER</ref>
641  <ref type="function">QUEUE_MEMBER_COUNT</ref>
642  <ref type="function">QUEUE_EXISTS</ref>
643  <ref type="function">QUEUE_GET_CHANNEL</ref>
644  <ref type="function">QUEUE_WAITING_COUNT</ref>
645  <ref type="function">QUEUE_MEMBER_LIST</ref>
646  <ref type="function">QUEUE_MEMBER_PENALTY</ref>
647  </see-also>
648  </function>
649  <function name="QUEUE_MEMBER_COUNT" language="en_US">
650  <synopsis>
651  Count number of members answering a queue.
652  </synopsis>
653  <syntax>
654  <parameter name="queuename" required="true" />
655  </syntax>
656  <description>
657  <para>Returns the number of members currently associated with the specified <replaceable>queuename</replaceable>.</para>
658  <warning><para>This function has been deprecated in favor of the <literal>QUEUE_MEMBER()</literal> function</para></warning>
659  </description>
660  <see-also>
661  <ref type="application">Queue</ref>
662  <ref type="application">QueueLog</ref>
663  <ref type="application">AddQueueMember</ref>
664  <ref type="application">RemoveQueueMember</ref>
665  <ref type="application">PauseQueueMember</ref>
666  <ref type="application">UnpauseQueueMember</ref>
667  <ref type="function">QUEUE_VARIABLES</ref>
668  <ref type="function">QUEUE_MEMBER</ref>
669  <ref type="function">QUEUE_MEMBER_COUNT</ref>
670  <ref type="function">QUEUE_EXISTS</ref>
671  <ref type="function">QUEUE_GET_CHANNEL</ref>
672  <ref type="function">QUEUE_WAITING_COUNT</ref>
673  <ref type="function">QUEUE_MEMBER_LIST</ref>
674  <ref type="function">QUEUE_MEMBER_PENALTY</ref>
675  </see-also>
676  </function>
677  <function name="QUEUE_EXISTS" language="en_US">
678  <synopsis>
679  Check if a named queue exists on this server
680  </synopsis>
681  <syntax>
682  <parameter name="queuename" />
683  </syntax>
684  <description>
685  <para>Returns 1 if the specified queue exists, 0 if it does not</para>
686  </description>
687  <see-also>
688  <ref type="application">Queue</ref>
689  <ref type="application">QueueLog</ref>
690  <ref type="application">AddQueueMember</ref>
691  <ref type="application">RemoveQueueMember</ref>
692  <ref type="application">PauseQueueMember</ref>
693  <ref type="application">UnpauseQueueMember</ref>
694  <ref type="function">QUEUE_VARIABLES</ref>
695  <ref type="function">QUEUE_MEMBER</ref>
696  <ref type="function">QUEUE_MEMBER_COUNT</ref>
697  <ref type="function">QUEUE_EXISTS</ref>
698  <ref type="function">QUEUE_GET_CHANNEL</ref>
699  <ref type="function">QUEUE_WAITING_COUNT</ref>
700  <ref type="function">QUEUE_MEMBER_LIST</ref>
701  <ref type="function">QUEUE_MEMBER_PENALTY</ref>
702  </see-also>
703  </function>
704  <function name="QUEUE_GET_CHANNEL" language="en_US">
705  <synopsis>
706  Return caller at the specified position in a queue.
707  </synopsis>
708  <syntax>
709  <parameter name="queuename" required="true" />
710  <parameter name="position" />
711  </syntax>
712  <description>
713  <para>Returns the caller channel at <replaceable>position</replaceable> in the specified <replaceable>queuename</replaceable>.</para>
714  <para>If <replaceable>position</replaceable> is unspecified the first channel is returned.</para>
715  </description>
716  <see-also>
717  <ref type="application">Queue</ref>
718  <ref type="application">QueueLog</ref>
719  <ref type="application">AddQueueMember</ref>
720  <ref type="application">RemoveQueueMember</ref>
721  <ref type="application">PauseQueueMember</ref>
722  <ref type="application">UnpauseQueueMember</ref>
723  <ref type="function">QUEUE_VARIABLES</ref>
724  <ref type="function">QUEUE_MEMBER</ref>
725  <ref type="function">QUEUE_MEMBER_COUNT</ref>
726  <ref type="function">QUEUE_EXISTS</ref>
727  <ref type="function">QUEUE_WAITING_COUNT</ref>
728  <ref type="function">QUEUE_MEMBER_LIST</ref>
729  <ref type="function">QUEUE_MEMBER_PENALTY</ref>
730  </see-also>
731  </function>
732  <function name="QUEUE_WAITING_COUNT" language="en_US">
733  <synopsis>
734  Count number of calls currently waiting in a queue.
735  </synopsis>
736  <syntax>
737  <parameter name="queuename" />
738  </syntax>
739  <description>
740  <para>Returns the number of callers currently waiting in the specified <replaceable>queuename</replaceable>.</para>
741  </description>
742  <see-also>
743  <ref type="application">Queue</ref>
744  <ref type="application">QueueLog</ref>
745  <ref type="application">AddQueueMember</ref>
746  <ref type="application">RemoveQueueMember</ref>
747  <ref type="application">PauseQueueMember</ref>
748  <ref type="application">UnpauseQueueMember</ref>
749  <ref type="function">QUEUE_VARIABLES</ref>
750  <ref type="function">QUEUE_MEMBER</ref>
751  <ref type="function">QUEUE_MEMBER_COUNT</ref>
752  <ref type="function">QUEUE_EXISTS</ref>
753  <ref type="function">QUEUE_GET_CHANNEL</ref>
754  <ref type="function">QUEUE_WAITING_COUNT</ref>
755  <ref type="function">QUEUE_MEMBER_LIST</ref>
756  <ref type="function">QUEUE_MEMBER_PENALTY</ref>
757  </see-also>
758  </function>
759  <function name="QUEUE_MEMBER_LIST" language="en_US">
760  <synopsis>
761  Returns a list of interfaces on a queue.
762  </synopsis>
763  <syntax>
764  <parameter name="queuename" required="true" />
765  </syntax>
766  <description>
767  <para>Returns a comma-separated list of members associated with the specified <replaceable>queuename</replaceable>.</para>
768  </description>
769  <see-also>
770  <ref type="application">Queue</ref>
771  <ref type="application">QueueLog</ref>
772  <ref type="application">AddQueueMember</ref>
773  <ref type="application">RemoveQueueMember</ref>
774  <ref type="application">PauseQueueMember</ref>
775  <ref type="application">UnpauseQueueMember</ref>
776  <ref type="function">QUEUE_VARIABLES</ref>
777  <ref type="function">QUEUE_MEMBER</ref>
778  <ref type="function">QUEUE_MEMBER_COUNT</ref>
779  <ref type="function">QUEUE_EXISTS</ref>
780  <ref type="function">QUEUE_GET_CHANNEL</ref>
781  <ref type="function">QUEUE_WAITING_COUNT</ref>
782  <ref type="function">QUEUE_MEMBER_LIST</ref>
783  <ref type="function">QUEUE_MEMBER_PENALTY</ref>
784  </see-also>
785  </function>
786  <function name="QUEUE_MEMBER_PENALTY" language="en_US">
787  <synopsis>
788  Gets or sets queue members penalty.
789  </synopsis>
790  <syntax>
791  <parameter name="queuename" required="true" />
792  <parameter name="interface" required="true" />
793  </syntax>
794  <description>
795  <para>Gets or sets queue members penalty.</para>
796  <warning><para>This function has been deprecated in favor of the <literal>QUEUE_MEMBER()</literal> function</para></warning>
797  </description>
798  <see-also>
799  <ref type="application">Queue</ref>
800  <ref type="application">QueueLog</ref>
801  <ref type="application">AddQueueMember</ref>
802  <ref type="application">RemoveQueueMember</ref>
803  <ref type="application">PauseQueueMember</ref>
804  <ref type="application">UnpauseQueueMember</ref>
805  <ref type="function">QUEUE_VARIABLES</ref>
806  <ref type="function">QUEUE_MEMBER</ref>
807  <ref type="function">QUEUE_MEMBER_COUNT</ref>
808  <ref type="function">QUEUE_EXISTS</ref>
809  <ref type="function">QUEUE_GET_CHANNEL</ref>
810  <ref type="function">QUEUE_WAITING_COUNT</ref>
811  <ref type="function">QUEUE_MEMBER_LIST</ref>
812  <ref type="function">QUEUE_MEMBER_PENALTY</ref>
813  </see-also>
814  </function>
815  <manager name="QueueStatus" language="en_US">
816  <synopsis>
817  Show queue status.
818  </synopsis>
819  <syntax>
820  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
821  <parameter name="Queue">
822  <para>Limit the response to the status of the specified queue.</para>
823  </parameter>
824  <parameter name="Member">
825  <para>Limit the response to the status of the specified member.</para>
826  </parameter>
827  </syntax>
828  <description>
829  <para>Check the status of one or more queues.</para>
830  </description>
831  </manager>
832  <manager name="QueueSummary" language="en_US">
833  <synopsis>
834  Show queue summary.
835  </synopsis>
836  <syntax>
837  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
838  <parameter name="Queue">
839  <para>Queue for which the summary is requested.</para>
840  </parameter>
841  </syntax>
842  <description>
843  <para>Request the manager to send a QueueSummary event.</para>
844  </description>
845  </manager>
846  <manager name="QueueAdd" language="en_US">
847  <synopsis>
848  Add interface to queue.
849  </synopsis>
850  <syntax>
851  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
852  <parameter name="Queue" required="true">
853  <para>Queue's name.</para>
854  </parameter>
855  <parameter name="Interface" required="true">
856  <para>The name of the interface (tech/name) to add to the queue.</para>
857  </parameter>
858  <parameter name="Penalty">
859  <para>A penalty (number) to apply to this member. Asterisk will distribute calls to members with higher penalties only after attempting to distribute calls to those with lower penalty.</para>
860  </parameter>
861  <parameter name="Paused">
862  <para>To pause or not the member initially (true/false or 1/0).</para>
863  </parameter>
864  <parameter name="MemberName">
865  <para>Text alias for the interface.</para>
866  </parameter>
867  <parameter name="StateInterface" />
868  </syntax>
869  <description>
870  </description>
871  </manager>
872  <manager name="QueueRemove" language="en_US">
873  <synopsis>
874  Remove interface from queue.
875  </synopsis>
876  <syntax>
877  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
878  <parameter name="Queue" required="true">
879  <para>The name of the queue to take action on.</para>
880  </parameter>
881  <parameter name="Interface" required="true">
882  <para>The interface (tech/name) to remove from queue.</para>
883  </parameter>
884  </syntax>
885  <description>
886  </description>
887  </manager>
888  <manager name="QueuePause" language="en_US">
889  <synopsis>
890  Makes a queue member temporarily unavailable.
891  </synopsis>
892  <syntax>
893  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
894  <parameter name="Interface" required="true">
895  <para>The name of the interface (tech/name) to pause or unpause.</para>
896  </parameter>
897  <parameter name="Paused" required="true">
898  <para>Pause or unpause the interface. Set to 'true' to pause the member or 'false' to unpause.</para>
899  </parameter>
900  <parameter name="Queue">
901  <para>The name of the queue in which to pause or unpause this member. If not specified, the member will be paused or unpaused in all the queues it is a member of.</para>
902  </parameter>
903  <parameter name="Reason">
904  <para>Text description, returned in the event QueueMemberPaused.</para>
905  </parameter>
906  </syntax>
907  <description>
908  <para>Pause or unpause a member in a queue.</para>
909  </description>
910  </manager>
911  <manager name="QueueLog" language="en_US">
912  <synopsis>
913  Adds custom entry in queue_log.
914  </synopsis>
915  <syntax>
916  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
917  <parameter name="Queue" required="true" />
918  <parameter name="Event" required="true" />
919  <parameter name="Uniqueid" />
920  <parameter name="Interface" />
921  <parameter name="Message" />
922  </syntax>
923  <description>
924  </description>
925  </manager>
926  <manager name="QueuePenalty" language="en_US">
927  <synopsis>
928  Set the penalty for a queue member.
929  </synopsis>
930  <syntax>
931  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
932  <parameter name="Interface" required="true">
933  <para>The interface (tech/name) of the member whose penalty to change.</para>
934  </parameter>
935  <parameter name="Penalty" required="true">
936  <para>The new penalty (number) for the member. Must be nonnegative.</para>
937  </parameter>
938  <parameter name="Queue">
939  <para>If specified, only set the penalty for the member of this queue. Otherwise, set the penalty for the member in all queues to which the member belongs.</para>
940  </parameter>
941  </syntax>
942  <description>
943  <para>Change the penalty of a queue member</para>
944  </description>
945  </manager>
946  <manager name="QueueMemberRingInUse" language="en_US">
947  <synopsis>
948  Set the ringinuse value for a queue member.
949  </synopsis>
950  <syntax>
951  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
952  <parameter name="Interface" required="true" />
953  <parameter name="RingInUse" required="true" />
954  <parameter name="Queue" />
955  </syntax>
956  <description>
957  </description>
958  </manager>
959  <manager name="QueueRule" language="en_US">
960  <synopsis>
961  Queue Rules.
962  </synopsis>
963  <syntax>
964  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
965  <parameter name="Rule">
966  <para>The name of the rule in queuerules.conf whose contents to list.</para>
967  </parameter>
968  </syntax>
969  <description>
970  <para>List queue rules defined in queuerules.conf</para>
971  </description>
972  </manager>
973  <manager name="QueueReload" language="en_US">
974  <synopsis>
975  Reload a queue, queues, or any sub-section of a queue or queues.
976  </synopsis>
977  <syntax>
978  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
979  <parameter name="Queue">
980  <para>The name of the queue to take action on. If no queue name is specified, then all queues are affected.</para>
981  </parameter>
982  <parameter name="Members">
983  <para>Whether to reload the queue's members.</para>
984  <enumlist>
985  <enum name="yes" />
986  <enum name="no" />
987  </enumlist>
988  </parameter>
989  <parameter name="Rules">
990  <para>Whether to reload queuerules.conf</para>
991  <enumlist>
992  <enum name="yes" />
993  <enum name="no" />
994  </enumlist>
995  </parameter>
996  <parameter name="Parameters">
997  <para>Whether to reload the other queue options.</para>
998  <enumlist>
999  <enum name="yes" />
1000  <enum name="no" />
1001  </enumlist>
1002  </parameter>
1003  </syntax>
1004  <description>
1005  </description>
1006  </manager>
1007  <manager name="QueueReset" language="en_US">
1008  <synopsis>
1009  Reset queue statistics.
1010  </synopsis>
1011  <syntax>
1012  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1013  <parameter name="Queue">
1014  <para>The name of the queue on which to reset statistics.</para>
1015  </parameter>
1016  </syntax>
1017  <description>
1018  <para>Reset the statistics for a queue.</para>
1019  </description>
1020  </manager>
1021  <manager name="QueueChangePriorityCaller" language="en_US">
1022  <synopsis>
1023  Change priority of a caller on queue.
1024  </synopsis>
1025  <syntax>
1026  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1027  <parameter name="Queue" required="true">
1028  <para>The name of the queue to take action on.</para>
1029  </parameter>
1030  <parameter name="Caller" required="true">
1031  <para>The caller (channel) to change priority on queue.</para>
1032  </parameter>
1033 
1034  <parameter name="Priority" required="true">
1035  <para>Priority value for change for caller on queue.</para>
1036  </parameter>
1037  </syntax>
1038  <description>
1039  </description>
1040  </manager>
1041 
1042  <managerEvent language="en_US" name="QueueMemberStatus">
1043  <managerEventInstance class="EVENT_FLAG_AGENT">
1044  <synopsis>Raised when a Queue member's status has changed.</synopsis>
1045  <syntax>
1046  <parameter name="Queue">
1047  <para>The name of the queue.</para>
1048  </parameter>
1049  <parameter name="MemberName">
1050  <para>The name of the queue member.</para>
1051  </parameter>
1052  <parameter name="Interface">
1053  <para>The queue member's channel technology or location.</para>
1054  </parameter>
1055  <parameter name="StateInterface">
1056  <para>Channel technology or location from which to read device state changes.</para>
1057  </parameter>
1058  <parameter name="Membership">
1059  <enumlist>
1060  <enum name="dynamic"/>
1061  <enum name="realtime"/>
1062  <enum name="static"/>
1063  </enumlist>
1064  </parameter>
1065  <parameter name="Penalty">
1066  <para>The penalty associated with the queue member.</para>
1067  </parameter>
1068  <parameter name="CallsTaken">
1069  <para>The number of calls this queue member has serviced.</para>
1070  </parameter>
1071  <parameter name="LastCall">
1072  <para>The time this member last took a call, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
1073  </parameter>
1074  <parameter name="LastPause">
1075  <para>The time when started last paused the queue member.</para>
1076  </parameter>
1077  <parameter name="InCall">
1078  <para>Set to 1 if member is in call. Set to 0 after LastCall time is updated.</para>
1079  <enumlist>
1080  <enum name="0"/>
1081  <enum name="1"/>
1082  </enumlist>
1083  </parameter>
1084  <parameter name="Status">
1085  <para>The numeric device state status of the queue member.</para>
1086  <enumlist>
1087  <enum name="0"><para>AST_DEVICE_UNKNOWN</para></enum>
1088  <enum name="1"><para>AST_DEVICE_NOT_INUSE</para></enum>
1089  <enum name="2"><para>AST_DEVICE_INUSE</para></enum>
1090  <enum name="3"><para>AST_DEVICE_BUSY</para></enum>
1091  <enum name="4"><para>AST_DEVICE_INVALID</para></enum>
1092  <enum name="5"><para>AST_DEVICE_UNAVAILABLE</para></enum>
1093  <enum name="6"><para>AST_DEVICE_RINGING</para></enum>
1094  <enum name="7"><para>AST_DEVICE_RINGINUSE</para></enum>
1095  <enum name="8"><para>AST_DEVICE_ONHOLD</para></enum>
1096  </enumlist>
1097  </parameter>
1098  <parameter name="Paused">
1099  <enumlist>
1100  <enum name="0"/>
1101  <enum name="1"/>
1102  </enumlist>
1103  </parameter>
1104  <parameter name="PausedReason">
1105  <para>If set when paused, the reason the queue member was paused.</para>
1106  </parameter>
1107  <parameter name="Ringinuse">
1108  <enumlist>
1109  <enum name="0"/>
1110  <enum name="1"/>
1111  </enumlist>
1112  </parameter>
1113  <parameter name="Wrapuptime">
1114  <para>The Wrapup Time of the queue member. If this value is set will override the wrapup time of queue.</para>
1115  </parameter>
1116  </syntax>
1117  </managerEventInstance>
1118  </managerEvent>
1119  <managerEvent language="en_US" name="QueueMemberAdded">
1120  <managerEventInstance class="EVENT_FLAG_AGENT">
1121  <synopsis>Raised when a member is added to the queue.</synopsis>
1122  <syntax>
1123  <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
1124  </syntax>
1125  <see-also>
1126  <ref type="managerEvent">QueueMemberRemoved</ref>
1127  <ref type="application">AddQueueMember</ref>
1128  </see-also>
1129  </managerEventInstance>
1130  </managerEvent>
1131  <managerEvent language="en_US" name="QueueMemberRemoved">
1132  <managerEventInstance class="EVENT_FLAG_AGENT">
1133  <synopsis>Raised when a member is removed from the queue.</synopsis>
1134  <syntax>
1135  <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
1136  </syntax>
1137  <see-also>
1138  <ref type="managerEvent">QueueMemberAdded</ref>
1139  <ref type="application">RemoveQueueMember</ref>
1140  </see-also>
1141  </managerEventInstance>
1142  </managerEvent>
1143  <managerEvent language="en_US" name="QueueMemberPause">
1144  <managerEventInstance class="EVENT_FLAG_AGENT">
1145  <synopsis>Raised when a member is paused/unpaused in the queue.</synopsis>
1146  <syntax>
1147  <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
1148  </syntax>
1149  <see-also>
1150  <ref type="application">PauseQueueMember</ref>
1151  <ref type="application">UnPauseQueueMember</ref>
1152  </see-also>
1153  </managerEventInstance>
1154  </managerEvent>
1155  <managerEvent language="en_US" name="QueueMemberPenalty">
1156  <managerEventInstance class="EVENT_FLAG_AGENT">
1157  <synopsis>Raised when a member's penalty is changed.</synopsis>
1158  <syntax>
1159  <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
1160  </syntax>
1161  <see-also>
1162  <ref type="function">QUEUE_MEMBER</ref>
1163  </see-also>
1164  </managerEventInstance>
1165  </managerEvent>
1166  <managerEvent language="en_US" name="QueueMemberRinginuse">
1167  <managerEventInstance class="EVENT_FLAG_AGENT">
1168  <synopsis>Raised when a member's ringinuse setting is changed.</synopsis>
1169  <syntax>
1170  <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
1171  </syntax>
1172  <see-also>
1173  <ref type="function">QUEUE_MEMBER</ref>
1174  </see-also>
1175  </managerEventInstance>
1176  </managerEvent>
1177  <managerEvent language="en_US" name="QueueCallerJoin">
1178  <managerEventInstance class="EVENT_FLAG_AGENT">
1179  <synopsis>Raised when a caller joins a Queue.</synopsis>
1180  <syntax>
1181  <channel_snapshot/>
1182  <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1183  <parameter name="Position">
1184  <para>This channel's current position in the queue.</para>
1185  </parameter>
1186  <parameter name="Count">
1187  <para>The total number of channels in the queue.</para>
1188  </parameter>
1189  </syntax>
1190  <see-also>
1191  <ref type="managerEvent">QueueCallerLeave</ref>
1192  <ref type="application">Queue</ref>
1193  </see-also>
1194  </managerEventInstance>
1195  </managerEvent>
1196  <managerEvent language="en_US" name="QueueCallerLeave">
1197  <managerEventInstance class="EVENT_FLAG_AGENT">
1198  <synopsis>Raised when a caller leaves a Queue.</synopsis>
1199  <syntax>
1200  <channel_snapshot/>
1201  <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1202  <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerJoin']/managerEventInstance/syntax/parameter[@name='Count'])" />
1203  <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerJoin']/managerEventInstance/syntax/parameter[@name='Position'])" />
1204  </syntax>
1205  <see-also>
1206  <ref type="managerEvent">QueueCallerJoin</ref>
1207  </see-also>
1208  </managerEventInstance>
1209  </managerEvent>
1210  <managerEvent language="en_US" name="QueueCallerAbandon">
1211  <managerEventInstance class="EVENT_FLAG_AGENT">
1212  <synopsis>Raised when a caller abandons the queue.</synopsis>
1213  <syntax>
1214  <channel_snapshot/>
1215  <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1216  <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerJoin']/managerEventInstance/syntax/parameter[@name='Position'])" />
1217  <parameter name="OriginalPosition">
1218  <para>The channel's original position in the queue.</para>
1219  </parameter>
1220  <parameter name="HoldTime">
1221  <para>The time the channel was in the queue, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
1222  </parameter>
1223  </syntax>
1224  </managerEventInstance>
1225  </managerEvent>
1226  <managerEvent language="en_US" name="AgentCalled">
1227  <managerEventInstance class="EVENT_FLAG_AGENT">
1228  <synopsis>Raised when an queue member is notified of a caller in the queue.</synopsis>
1229  <syntax>
1230  <channel_snapshot/>
1231  <channel_snapshot prefix="Dest"/>
1232  <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1233  <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
1234  <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
1235  </syntax>
1236  <see-also>
1237  <ref type="managerEvent">AgentRingNoAnswer</ref>
1238  <ref type="managerEvent">AgentComplete</ref>
1239  <ref type="managerEvent">AgentConnect</ref>
1240  </see-also>
1241  </managerEventInstance>
1242  </managerEvent>
1243  <managerEvent language="en_US" name="AgentRingNoAnswer">
1244  <managerEventInstance class="EVENT_FLAG_AGENT">
1245  <synopsis>Raised when a queue member is notified of a caller in the queue and fails to answer.</synopsis>
1246  <syntax>
1247  <channel_snapshot/>
1248  <channel_snapshot prefix="Dest"/>
1249  <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1250  <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
1251  <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
1252  <parameter name="RingTime">
1253  <para>The time the queue member was rung, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
1254  </parameter>
1255  </syntax>
1256  <see-also>
1257  <ref type="managerEvent">AgentCalled</ref>
1258  </see-also>
1259  </managerEventInstance>
1260  </managerEvent>
1261  <managerEvent language="en_US" name="AgentComplete">
1262  <managerEventInstance class="EVENT_FLAG_AGENT">
1263  <synopsis>Raised when a queue member has finished servicing a caller in the queue.</synopsis>
1264  <syntax>
1265  <channel_snapshot/>
1266  <channel_snapshot prefix="Dest"/>
1267  <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1268  <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
1269  <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
1270  <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerAbandon']/managerEventInstance/syntax/parameter[@name='HoldTime'])" />
1271  <parameter name="TalkTime">
1272  <para>The time the queue member talked with the caller in the queue, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
1273  </parameter>
1274  <parameter name="Reason">
1275  <enumlist>
1276  <enum name="caller"/>
1277  <enum name="agent"/>
1278  <enum name="transfer"/>
1279  </enumlist>
1280  </parameter>
1281  </syntax>
1282  <see-also>
1283  <ref type="managerEvent">AgentCalled</ref>
1284  <ref type="managerEvent">AgentConnect</ref>
1285  </see-also>
1286  </managerEventInstance>
1287  </managerEvent>
1288  <managerEvent language="en_US" name="AgentDump">
1289  <managerEventInstance class="EVENT_FLAG_AGENT">
1290  <synopsis>Raised when a queue member hangs up on a caller in the queue.</synopsis>
1291  <syntax>
1292  <channel_snapshot/>
1293  <channel_snapshot prefix="Dest"/>
1294  <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1295  <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
1296  <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
1297  </syntax>
1298  <see-also>
1299  <ref type="managerEvent">AgentCalled</ref>
1300  <ref type="managerEvent">AgentConnect</ref>
1301  </see-also>
1302  </managerEventInstance>
1303  </managerEvent>
1304  <managerEvent language="en_US" name="AgentConnect">
1305  <managerEventInstance class="EVENT_FLAG_AGENT">
1306  <synopsis>Raised when a queue member answers and is bridged to a caller in the queue.</synopsis>
1307  <syntax>
1308  <channel_snapshot/>
1309  <channel_snapshot prefix="Dest"/>
1310  <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1311  <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
1312  <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
1313  <xi:include xpointer="xpointer(/docs/managerEvent[@name='AgentRingNoAnswer']/managerEventInstance/syntax/parameter[@name='RingTime'])" />
1314  <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerAbandon']/managerEventInstance/syntax/parameter[@name='HoldTime'])" />
1315  </syntax>
1316  <see-also>
1317  <ref type="managerEvent">AgentCalled</ref>
1318  <ref type="managerEvent">AgentComplete</ref>
1319  <ref type="managerEvent">AgentDump</ref>
1320  </see-also>
1321  </managerEventInstance>
1322  </managerEvent>
1323  ***/
1324 
1325 enum {
1327  OPT_GO_ON = (1 << 1),
1328  OPT_DATA_QUALITY = (1 << 2),
1329  OPT_CALLEE_GO_ON = (1 << 3),
1330  OPT_CALLEE_HANGUP = (1 << 4),
1331  OPT_CALLER_HANGUP = (1 << 5),
1334  OPT_CALLEE_PARK = (1 << 8),
1335  OPT_CALLER_PARK = (1 << 9),
1336  OPT_NO_RETRY = (1 << 10),
1337  OPT_RINGING = (1 << 11),
1339  OPT_CALLEE_TRANSFER = (1 << 13),
1340  OPT_CALLER_TRANSFER = (1 << 14),
1343  OPT_CALLEE_AUTOMON = (1 << 17),
1344  OPT_CALLER_AUTOMON = (1 << 18),
1345  OPT_PREDIAL_CALLEE = (1 << 19),
1346  OPT_PREDIAL_CALLER = (1 << 20),
1347 };
1348 
1349 enum {
1353  /* note: this entry _MUST_ be the last one in the enum */
1355 };
1356 
1361  AST_APP_OPTION('c', OPT_GO_ON),
1380 
1381 enum {
1390 };
1391 
1392 enum {
1396 };
1397 
1402  QUEUE_RESET_STATS = (1 << 3),
1403 };
1404 
1405 static const struct strategy {
1407  const char *name;
1408 } strategies[] = {
1409  { QUEUE_STRATEGY_RINGALL, "ringall" },
1410  { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
1411  { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
1412  { QUEUE_STRATEGY_RANDOM, "random" },
1413  { QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
1414  { QUEUE_STRATEGY_RRMEMORY, "roundrobin" },
1415  { QUEUE_STRATEGY_LINEAR, "linear" },
1416  { QUEUE_STRATEGY_WRANDOM, "wrandom"},
1417  { QUEUE_STRATEGY_RRORDERED, "rrordered"},
1418 };
1419 
1420 static const struct autopause {
1422  const char *name;
1423 } autopausesmodes [] = {
1424  { QUEUE_AUTOPAUSE_OFF,"no" },
1425  { QUEUE_AUTOPAUSE_ON, "yes" },
1426  { QUEUE_AUTOPAUSE_ALL,"all" },
1427 };
1428 
1429 #define DEFAULT_RETRY 5
1430 #define DEFAULT_TIMEOUT 15
1431 #define RECHECK 1 /*!< Recheck every second to see we we're at the top yet */
1432 #define MAX_PERIODIC_ANNOUNCEMENTS 10 /*!< The maximum periodic announcements we can have */
1433 /*!
1434  * \brief The minimum number of seconds between position announcements.
1435  * \note The default value of 15 provides backwards compatibility.
1436  */
1437 #define DEFAULT_MIN_ANNOUNCE_FREQUENCY 15
1438 
1439 #define MAX_QUEUE_BUCKETS 53
1440 
1441 #define RES_OKAY 0 /*!< Action completed */
1442 #define RES_EXISTS (-1) /*!< Entry already exists */
1443 #define RES_OUTOFMEMORY (-2) /*!< Out of memory */
1444 #define RES_NOSUCHQUEUE (-3) /*!< No such queue */
1445 #define RES_NOT_DYNAMIC (-4) /*!< Member is not dynamic */
1446 #define RES_NOT_CALLER (-5) /*!< Caller not found */
1447 
1448 static char *app = "Queue";
1449 
1450 static char *app_aqm = "AddQueueMember" ;
1451 
1452 static char *app_rqm = "RemoveQueueMember" ;
1453 
1454 static char *app_pqm = "PauseQueueMember" ;
1455 
1456 static char *app_upqm = "UnpauseQueueMember" ;
1457 
1458 static char *app_ql = "QueueLog" ;
1459 
1460 static char *app_qupd = "QueueUpdate";
1461 
1462 /*! \brief Persistent Members astdb family */
1463 static const char * const pm_family = "Queue/PersistentMembers";
1464 
1465 /*! \brief queues.conf [general] option */
1467 
1468 /*! \brief Records that one or more queues use weight */
1469 static int use_weight;
1470 
1471 /*! \brief queues.conf [general] option */
1472 static int autofill_default;
1473 
1474 /*! \brief queues.conf [general] option */
1475 static int montype_default;
1476 
1477 /*! \brief queues.conf [general] option */
1478 static int shared_lastcall;
1479 
1480 /*! \brief queuesrules.conf [general] option */
1481 static int realtime_rules;
1482 
1483 /*! \brief Subscription to device state change messages */
1485 
1486 /*! \brief queues.conf [general] option */
1488 
1489 /*! \brief queues.conf [general] option */
1491 
1492 /*! \brief name of the ringinuse field in the realtime database */
1494 
1504 };
1505 
1506 static const struct {
1508  char *text;
1509 } queue_results[] = {
1510  { QUEUE_UNKNOWN, "UNKNOWN" },
1511  { QUEUE_TIMEOUT, "TIMEOUT" },
1512  { QUEUE_JOINEMPTY,"JOINEMPTY" },
1513  { QUEUE_LEAVEEMPTY, "LEAVEEMPTY" },
1514  { QUEUE_JOINUNAVAIL, "JOINUNAVAIL" },
1515  { QUEUE_LEAVEUNAVAIL, "LEAVEUNAVAIL" },
1516  { QUEUE_FULL, "FULL" },
1517  { QUEUE_CONTINUE, "CONTINUE" },
1518 };
1519 
1523 };
1524 
1525 /*! \brief We define a custom "local user" structure because we
1526  * use it not only for keeping track of what is in use but
1527  * also for keeping track of who we're dialing.
1528  *
1529  * There are two "links" defined in this structure, q_next and call_next.
1530  * q_next links ALL defined callattempt structures into a linked list. call_next is
1531  * a link which allows for a subset of the callattempts to be traversed. This subset
1532  * is used in wait_for_answer so that irrelevant callattempts are not traversed. This
1533  * also is helpful so that queue logs are always accurate in the case where a call to
1534  * a member times out, especially if using the ringall strategy.
1535 */
1536 
1537 struct callattempt {
1541  char interface[256]; /*!< An Asterisk dial string (not a channel name) */
1542  int metric;
1543  struct member *member;
1544  /*! Saved connected party info from an AST_CONTROL_CONNECTED_LINE. */
1546  /*! TRUE if an AST_CONTROL_CONNECTED_LINE update was saved to the connected element. */
1548  /*! TRUE if the connected line update is blocked. */
1549  unsigned int block_connected_update:1;
1550  /*! TRUE if caller id is not available for connected line */
1551  unsigned int dial_callerid_absent:1;
1552  /*! TRUE if the call is still active */
1553  unsigned int stillgoing:1;
1555  /*! Original channel name. Must be freed. Could be NULL if allocation failed. */
1557 };
1558 
1559 
1560 struct queue_ent {
1561  struct call_queue *parent; /*!< What queue is our parent */
1562  char moh[MAX_MUSICCLASS]; /*!< Name of musiconhold to be used */
1563  char announce[PATH_MAX]; /*!< Announcement to play for member when call is answered */
1564  char context[AST_MAX_CONTEXT]; /*!< Context when user exits queue */
1565  char digits[AST_MAX_EXTENSION]; /*!< Digits entered while in queue */
1566  const char *predial_callee; /*!< Gosub app arguments for outgoing calls. NULL if not supplied. */
1567  int valid_digits; /*!< Digits entered correspond to valid extension. Exited */
1568  int pos; /*!< Where we are in the queue */
1569  int prio; /*!< Our priority */
1570  int last_pos_said; /*!< Last position we told the user */
1571  int ring_when_ringing; /*!< Should we only use ring indication when a channel is ringing? */
1572  time_t last_periodic_announce_time; /*!< The last time we played a periodic announcement */
1573  int last_periodic_announce_sound; /*!< The last periodic announcement we made */
1574  time_t last_pos; /*!< Last time we told the user their position */
1575  int opos; /*!< Where we started in the queue */
1576  int handled; /*!< Whether our call was handled */
1577  int pending; /*!< Non-zero if we are attempting to call a member */
1578  int max_penalty; /*!< Limit the members that can take this call to this penalty or lower */
1579  int min_penalty; /*!< Limit the members that can take this call to this penalty or higher */
1580  int raise_penalty; /*!< Float lower penalty mambers to a minimum penalty */
1581  int linpos; /*!< If using linear strategy, what position are we at? */
1582  int linwrapped; /*!< Is the linpos wrapped? */
1583  time_t start; /*!< When we started holding */
1584  time_t expire; /*!< When this entry should expire (time out of queue) */
1585  int cancel_answered_elsewhere; /*!< Whether we should force the CAE flag on this call (C) option*/
1586  struct ast_channel *chan; /*!< Our channel */
1587  AST_LIST_HEAD_NOLOCK(,penalty_rule) qe_rules; /*!< Local copy of the queue's penalty rules */
1588  struct penalty_rule *pr; /*!< Pointer to the next penalty rule to implement */
1589  struct queue_ent *next; /*!< The next queue entry */
1590 };
1591 
1592 struct member {
1593  char interface[AST_CHANNEL_NAME]; /*!< Technology/Location to dial to reach this member*/
1594  char state_exten[AST_MAX_EXTENSION]; /*!< Extension to get state from (if using hint) */
1595  char state_context[AST_MAX_CONTEXT]; /*!< Context to use when getting state (if using hint) */
1596  char state_interface[AST_CHANNEL_NAME]; /*!< Technology/Location from which to read devicestate changes */
1597  int state_id; /*!< Extension state callback id (if using hint) */
1598  char membername[80]; /*!< Member name to use in queue logs */
1599  int penalty; /*!< Are we a last resort? */
1600  int calls; /*!< Number of calls serviced by this member */
1601  int dynamic; /*!< Are we dynamically added? */
1602  int realtime; /*!< Is this member realtime? */
1603  int status; /*!< Status of queue member */
1604  int paused; /*!< Are we paused (not accepting calls)? */
1605  char reason_paused[80]; /*!< Reason of paused if member is paused */
1606  int queuepos; /*!< In what order (pertains to certain strategies) should this member be called? */
1607  int callcompletedinsl; /*!< Whether the current call was completed within service level */
1608  int wrapuptime; /*!< Wrapup Time */
1609  time_t starttime; /*!< The time at which the member answered the current caller. */
1610  time_t lastcall; /*!< When last successful call was hungup */
1611  time_t lastpause; /*!< When started the last pause */
1612  struct call_queue *lastqueue; /*!< Last queue we received a call */
1613  unsigned int dead:1; /*!< Used to detect members deleted in realtime */
1614  unsigned int delme:1; /*!< Flag to delete entry on reload */
1615  char rt_uniqueid[80]; /*!< Unique id of realtime member entry */
1616  unsigned int ringinuse:1; /*!< Flag to ring queue members even if their status is 'inuse' */
1617 };
1618 
1622  QUEUE_EMPTY_INUSE = (1 << 2),
1628 };
1629 
1633 };
1634 
1635 /* values used in multi-bit flags in call_queue */
1636 #define ANNOUNCEHOLDTIME_ALWAYS 1
1637 #define ANNOUNCEHOLDTIME_ONCE 2
1638 #define QUEUE_EVENT_VARIABLES 3
1639 
1641  int time; /*!< Number of seconds that need to pass before applying this rule */
1642  int max_value; /*!< The amount specified in the penalty rule for max penalty */
1643  int min_value; /*!< The amount specified in the penalty rule for min penalty */
1644  int raise_value; /*!< The amount specified in the penalty rule for min penalty */
1645  int max_relative; /*!< Is the max adjustment relative? 1 for relative, 0 for absolute */
1646  int min_relative; /*!< Is the min adjustment relative? 1 for relative, 0 for absolute */
1647  int raise_relative; /*!< Is the min adjustment relative? 1 for relative, 0 for absolute */
1648  AST_LIST_ENTRY(penalty_rule) list; /*!< Next penalty_rule */
1649 };
1650 
1651 #define ANNOUNCEPOSITION_YES 1 /*!< We announce position */
1652 #define ANNOUNCEPOSITION_NO 2 /*!< We don't announce position */
1653 #define ANNOUNCEPOSITION_MORE_THAN 3 /*!< We say "Currently there are more than <limit>" */
1654 #define ANNOUNCEPOSITION_LIMIT 4 /*!< We not announce position more than <limit> */
1655 
1656 struct call_queue {
1658  /*! Queue name */
1660  /*! Music on Hold class */
1661  AST_STRING_FIELD(moh);
1662  /*! Announcement to play when call is answered */
1663  AST_STRING_FIELD(announce);
1664  /*! Exit context */
1666  /*! Macro to run upon member connection */
1667  AST_STRING_FIELD(membermacro);
1668  /*! Gosub to run upon member connection */
1669  AST_STRING_FIELD(membergosub);
1670  /*! Default rule to use if none specified in call to Queue() */
1671  AST_STRING_FIELD(defaultrule);
1672  /*! Sound file: "Your call is now first in line" (def. queue-youarenext) */
1673  AST_STRING_FIELD(sound_next);
1674  /*! Sound file: "There are currently" (def. queue-thereare) */
1675  AST_STRING_FIELD(sound_thereare);
1676  /*! Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting) */
1677  AST_STRING_FIELD(sound_calls);
1678  /*! Sound file: "Currently there are more than" (def. queue-quantity1) */
1679  AST_STRING_FIELD(queue_quantity1);
1680  /*! Sound file: "callers waiting to speak with a representative" (def. queue-quantity2) */
1681  AST_STRING_FIELD(queue_quantity2);
1682  /*! Sound file: "The current estimated total holdtime is" (def. queue-holdtime) */
1683  AST_STRING_FIELD(sound_holdtime);
1684  /*! Sound file: "minutes." (def. queue-minutes) */
1685  AST_STRING_FIELD(sound_minutes);
1686  /*! Sound file: "minute." (def. queue-minute) */
1687  AST_STRING_FIELD(sound_minute);
1688  /*! Sound file: "seconds." (def. queue-seconds) */
1689  AST_STRING_FIELD(sound_seconds);
1690  /*! Sound file: "Thank you for your patience." (def. queue-thankyou) */
1691  AST_STRING_FIELD(sound_thanks);
1692  /*! Sound file: Custom announce for caller, no default */
1693  AST_STRING_FIELD(sound_callerannounce);
1694  /*! Sound file: "Hold time" (def. queue-reporthold) */
1695  AST_STRING_FIELD(sound_reporthold);
1696  );
1697  /*! Sound files: Custom announce, no default */
1698  struct ast_str *sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS];
1699  unsigned int dead:1;
1700  unsigned int ringinuse:1;
1701  unsigned int announce_to_first_user:1; /*!< Whether or not we announce to the first user in a queue */
1702  unsigned int setinterfacevar:1;
1703  unsigned int setqueuevar:1;
1704  unsigned int setqueueentryvar:1;
1705  unsigned int reportholdtime:1;
1706  unsigned int wrapped:1;
1707  unsigned int timeoutrestart:1;
1708  unsigned int announceholdtime:2;
1709  unsigned int announceposition:3;
1710  unsigned int announceposition_only_up:1; /*!< Only announce position if it has improved */
1711  int strategy:4;
1712  unsigned int realtime:1;
1713  unsigned int found:1;
1715  unsigned int autopausebusy:1;
1716  unsigned int autopauseunavail:1;
1717  enum empty_conditions joinempty;
1718  enum empty_conditions leavewhenempty;
1719  int announcepositionlimit; /*!< How many positions we announce? */
1720  int announcefrequency; /*!< How often to announce their position */
1721  int minannouncefrequency; /*!< The minimum number of seconds between position announcements (def. 15) */
1722  int periodicannouncefrequency; /*!< How often to play periodic announcement */
1723  int numperiodicannounce; /*!< The number of periodic announcements configured */
1724  int randomperiodicannounce; /*!< Are periodic announcments randomly chosen */
1725  int roundingseconds; /*!< How many seconds do we round to? */
1726  int holdtime; /*!< Current avg holdtime, based on an exponential average */
1727  int talktime; /*!< Current avg talktime, based on the same exponential average */
1728  int callscompleted; /*!< Number of queue calls completed */
1729  int callsabandoned; /*!< Number of queue calls abandoned */
1730  int callsabandonedinsl; /*!< Number of queue calls abandoned in servicelevel */
1731  int servicelevel; /*!< seconds setting for servicelevel*/
1732  int callscompletedinsl; /*!< Number of calls answered with servicelevel*/
1733  char monfmt[8]; /*!< Format to use when recording calls */
1734  int montype; /*!< Monitor type Monitor vs. MixMonitor */
1735  int count; /*!< How many entries */
1736  int maxlen; /*!< Max number of entries */
1737  int wrapuptime; /*!< Wrapup Time */
1738  int penaltymemberslimit; /*!< Disregard penalty when queue has fewer than this many members */
1739 
1740  int retry; /*!< Retry calling everyone after this amount of time */
1741  int timeout; /*!< How long to wait for an answer */
1742  int weight; /*!< Respective weight */
1743  int autopause; /*!< Auto pause queue members if they fail to answer */
1744  int autopausedelay; /*!< Delay auto pause for autopausedelay seconds since last call */
1745  int timeoutpriority; /*!< Do we allow a fraction of the timeout to occur for a ring? */
1746 
1747  /* Queue strategy things */
1748  int rrpos; /*!< Round Robin - position */
1749  int memberdelay; /*!< Seconds to delay connecting member to caller */
1750  int autofill; /*!< Ignore the head call status and ring an available agent */
1751 
1752  struct ao2_container *members; /*!< Head of the list of members */
1753  struct queue_ent *head; /*!< Head of the list of callers */
1754  AST_LIST_ENTRY(call_queue) list; /*!< Next call queue */
1755  AST_LIST_HEAD_NOLOCK(, penalty_rule) rules; /*!< The list of penalty rules to invoke */
1756 };
1757 
1758 struct rule_list {
1759  char name[80];
1762 };
1763 
1765 
1766 static struct ao2_container *queues;
1767 
1768 static void update_realtime_members(struct call_queue *q);
1769 static struct member *interface_exists(struct call_queue *q, const char *interface);
1770 static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
1771 static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime);
1772 
1773 static struct member *find_member_by_queuename_and_interface(const char *queuename, const char *interface);
1774 /*! \brief sets the QUEUESTATUS channel variable */
1775 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
1776 {
1777  int i;
1778 
1779  for (i = 0; i < ARRAY_LEN(queue_results); i++) {
1780  if (queue_results[i].id == res) {
1781  pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
1782  return;
1783  }
1784  }
1785 }
1786 
1787 static const char *int2strat(int strategy)
1788 {
1789  int x;
1790 
1791  for (x = 0; x < ARRAY_LEN(strategies); x++) {
1792  if (strategy == strategies[x].strategy) {
1793  return strategies[x].name;
1794  }
1795  }
1796 
1797  return "<unknown>";
1798 }
1799 
1800 static int strat2int(const char *strategy)
1801 {
1802  int x;
1803 
1804  for (x = 0; x < ARRAY_LEN(strategies); x++) {
1805  if (!strcasecmp(strategy, strategies[x].name)) {
1806  return strategies[x].strategy;
1807  }
1808  }
1809 
1810  return -1;
1811 }
1812 
1813 static int autopause2int(const char *autopause)
1814 {
1815  int x;
1816  /*This 'double check' that default value is OFF */
1817  if (ast_strlen_zero(autopause)) {
1818  return QUEUE_AUTOPAUSE_OFF;
1819  }
1820 
1821  /*This 'double check' is to ensure old values works */
1822  if(ast_true(autopause)) {
1823  return QUEUE_AUTOPAUSE_ON;
1824  }
1825 
1826  for (x = 0; x < ARRAY_LEN(autopausesmodes); x++) {
1827  if (!strcasecmp(autopause, autopausesmodes[x].name)) {
1828  return autopausesmodes[x].autopause;
1829  }
1830  }
1831 
1832  /*This 'double check' that default value is OFF */
1833  return QUEUE_AUTOPAUSE_OFF;
1834 }
1835 
1836 static int queue_hash_cb(const void *obj, const int flags)
1837 {
1838  const struct call_queue *q = obj;
1839 
1840  return ast_str_case_hash(q->name);
1841 }
1842 
1843 static int queue_cmp_cb(void *obj, void *arg, int flags)
1844 {
1845  struct call_queue *q = obj, *q2 = arg;
1846  return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0;
1847 }
1848 
1849 /*!
1850  * \brief Return wrapuptime
1851  *
1852  * This function checks if wrapuptime in member is set and return this value.
1853  * Otherwise return value the wrapuptime in the queue configuration
1854  * \return integer value
1855  */
1856 static int get_wrapuptime(struct call_queue *q, struct member *member)
1857 {
1858  if (member->wrapuptime) {
1859  return member->wrapuptime;
1860  }
1861  return q->wrapuptime;
1862 }
1863 
1864 /*! \internal
1865  * \brief ao2_callback, Decreases queuepos of all followers with a queuepos greater than arg.
1866  * \param obj the member being acted on
1867  * \param arg pointer to an integer containing the position value that was removed and requires reduction for anything above
1868  */
1869 static int queue_member_decrement_followers(void *obj, void *arg, int flag)
1870 {
1871  struct member *mem = obj;
1872  int *decrement_followers_after = arg;
1873 
1874  if (mem->queuepos > *decrement_followers_after) {
1875  mem->queuepos--;
1876  }
1877 
1878  return 0;
1879 }
1880 
1881 /*! \internal
1882  * \brief ao2_callback, finds members in a queue marked for deletion and in a cascading fashion runs queue_member_decrement_followers
1883  * on them. This callback should always be ran before performing mass unlinking of delmarked members from queues.
1884  * \param obj member being acted on
1885  * \param arg pointer to the queue members are being removed from
1886  */
1887 static int queue_delme_members_decrement_followers(void *obj, void *arg, int flag)
1888 {
1889  struct member *mem = obj;
1890  struct call_queue *queue = arg;
1891  int rrpos = mem->queuepos;
1892 
1893  if (mem->delme) {
1895  }
1896 
1897  return 0;
1898 }
1899 
1900 /*! \internal
1901  * \brief Use this to decrement followers during removal of a member
1902  * \param queue which queue the member is being removed from
1903  * \param mem which member is being removed from the queue
1904  */
1905 static void queue_member_follower_removal(struct call_queue *queue, struct member *mem)
1906 {
1907  int pos = mem->queuepos;
1908 
1909  /* If the position being removed is less than the current place in the queue, reduce the queue position by one so that we don't skip the member
1910  * who would have been next otherwise. */
1911  if (pos < queue->rrpos) {
1912  queue->rrpos--;
1913  }
1914 
1916 }
1917 
1918 #define queue_ref(q) ao2_bump(q)
1919 #define queue_unref(q) ({ ao2_cleanup(q); NULL; })
1920 #define queue_t_ref(q, tag) ao2_t_bump(q, tag)
1921 #define queue_t_unref(q, tag) ({ ao2_t_cleanup(q, tag); NULL; })
1922 #define queues_t_link(c, q, tag) ao2_t_link(c, q, tag)
1923 #define queues_t_unlink(c, q, tag) ao2_t_unlink(c, q, tag)
1924 
1925 /*! \brief Set variables of queue */
1926 static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
1927 {
1928  char interfacevar[256]="";
1929  float sl = 0;
1930 
1931  ao2_lock(q);
1932 
1933  if (q->setqueuevar) {
1934  sl = 0;
1935  if (q->callscompleted > 0) {
1936  sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
1937  }
1938 
1939  snprintf(interfacevar, sizeof(interfacevar),
1940  "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
1941  q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned, q->servicelevel, sl);
1942 
1943  ao2_unlock(q);
1944 
1945  pbx_builtin_setvar_multiple(chan, interfacevar);
1946  } else {
1947  ao2_unlock(q);
1948  }
1949 }
1950 
1951 /*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
1952 static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
1953 {
1954  struct queue_ent *cur;
1955 
1956  if (!q || !new)
1957  return;
1958  if (prev) {
1959  cur = prev->next;
1960  prev->next = new;
1961  } else {
1962  cur = q->head;
1963  q->head = new;
1964  }
1965  new->next = cur;
1966 
1967  /* every queue_ent must have a reference to it's parent call_queue, this
1968  * reference does not go away until the end of the queue_ent's life, meaning
1969  * that even when the queue_ent leaves the call_queue this ref must remain. */
1970  queue_ref(q);
1971  new->parent = q;
1972  new->pos = ++(*pos);
1973  new->opos = *pos;
1974 }
1975 
1977 {
1978  struct ast_channel_blob *obj = stasis_message_data(message);
1979  RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
1980  RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
1981 
1982  channel_string = ast_manager_build_channel_state_string(obj->snapshot);
1983  event_string = ast_manager_str_from_json_object(obj->blob, NULL);
1984  if (!channel_string || !event_string) {
1985  return NULL;
1986  }
1987 
1989  "%s"
1990  "%s",
1991  ast_str_buffer(channel_string),
1992  ast_str_buffer(event_string));
1993 }
1994 
1996 {
1997  return queue_channel_to_ami("QueueCallerJoin", message);
1998 }
1999 
2001 {
2002  return queue_channel_to_ami("QueueCallerLeave", message);
2003 }
2004 
2006 {
2007  return queue_channel_to_ami("QueueCallerAbandon", message);
2008 }
2009 
2010 STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_caller_join_type,
2012  );
2013 STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_caller_leave_type,
2015  );
2016 STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_caller_abandon_type,
2018  );
2019 
2021 {
2022  struct ast_json_payload *payload = stasis_message_data(message);
2023  RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
2024 
2025  event_string = ast_manager_str_from_json_object(payload->json, NULL);
2026  if (!event_string) {
2027  return NULL;
2028  }
2029 
2031  "%s",
2032  ast_str_buffer(event_string));
2033 }
2034 
2036 {
2037  return queue_member_to_ami("QueueMemberStatus", message);
2038 }
2039 
2041 {
2042  return queue_member_to_ami("QueueMemberAdded", message);
2043 }
2044 
2046 {
2047  return queue_member_to_ami("QueueMemberRemoved", message);
2048 }
2049 
2051 {
2052  return queue_member_to_ami("QueueMemberPause", message);
2053 }
2054 
2056 {
2057  return queue_member_to_ami("QueueMemberPenalty", message);
2058 }
2059 
2061 {
2062  return queue_member_to_ami("QueueMemberRinginuse", message);
2063 }
2064 
2065 STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_status_type,
2067  );
2068 STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_added_type,
2070  );
2071 STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_removed_type,
2073  );
2074 STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_pause_type,
2076  );
2077 STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_penalty_type,
2079  );
2080 STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_ringinuse_type,
2082  );
2083 
2085 {
2086  struct ast_multi_channel_blob *obj = stasis_message_data(message);
2087  struct ast_channel_snapshot *caller;
2088  struct ast_channel_snapshot *agent;
2089  RAII_VAR(struct ast_str *, caller_event_string, NULL, ast_free);
2090  RAII_VAR(struct ast_str *, agent_event_string, NULL, ast_free);
2091  RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
2092 
2093  caller = ast_multi_channel_blob_get_channel(obj, "caller");
2094  if (caller) {
2095  caller_event_string = ast_manager_build_channel_state_string(caller);
2096  if (!caller_event_string) {
2097  ast_log(LOG_NOTICE, "No caller event string, bailing\n");
2098  return NULL;
2099  }
2100  }
2101 
2102  agent = ast_multi_channel_blob_get_channel(obj, "agent");
2103  if (agent) {
2104  agent_event_string = ast_manager_build_channel_state_string_prefix(agent, "Dest");
2105  if (!agent_event_string) {
2106  ast_log(LOG_NOTICE, "No agent event string, bailing\n");
2107  return NULL;
2108  }
2109  }
2110 
2112  if (!event_string) {
2113  return NULL;
2114  }
2115 
2117  "%s"
2118  "%s"
2119  "%s",
2120  caller_event_string ? ast_str_buffer(caller_event_string) : "",
2121  agent_event_string ? ast_str_buffer(agent_event_string) : "",
2122  ast_str_buffer(event_string));
2123 }
2124 
2126 {
2127  return queue_multi_channel_to_ami("AgentCalled", message);
2128 }
2129 
2131 {
2132  return queue_multi_channel_to_ami("AgentConnect", message);
2133 }
2134 
2136 {
2137  return queue_multi_channel_to_ami("AgentComplete", message);
2138 }
2139 
2141 {
2142  return queue_multi_channel_to_ami("AgentDump", message);
2143 }
2144 
2146 {
2147  return queue_multi_channel_to_ami("AgentRingNoAnswer", message);
2148 }
2149 
2150 STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_called_type,
2152  );
2153 STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_connect_type,
2155  );
2156 STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_complete_type,
2158  );
2159 STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_dump_type,
2161  );
2162 STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_ringnoanswer_type,
2164  );
2165 
2167  struct ast_channel_snapshot *caller_snapshot,
2168  struct ast_channel_snapshot *agent_snapshot,
2169  struct stasis_message_type *type, struct ast_json *blob)
2170 {
2171  RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
2172  RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
2173 
2174  if (!type) {
2175  return;
2176  }
2177 
2178  payload = ast_multi_channel_blob_create(blob);
2179  if (!payload) {
2180  return;
2181  }
2182 
2183  if (caller_snapshot) {
2184  ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot);
2185  } else {
2186  ast_debug(1, "Empty caller_snapshot; sending incomplete event\n");
2187  }
2188 
2189  if (agent_snapshot) {
2190  ast_multi_channel_blob_add_channel(payload, "agent", agent_snapshot);
2191  }
2192 
2193  msg = stasis_message_create(type, payload);
2194  if (!msg) {
2195  return;
2196  }
2197 
2198  stasis_publish(topic, msg);
2199 }
2200 
2201 static void queue_publish_multi_channel_blob(struct ast_channel *caller, struct ast_channel *agent,
2202  struct stasis_message_type *type, struct ast_json *blob)
2203 {
2204  RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
2205  RAII_VAR(struct ast_channel_snapshot *, agent_snapshot, NULL, ao2_cleanup);
2206 
2207  ast_channel_lock(caller);
2208  caller_snapshot = ast_channel_snapshot_create(caller);
2209  ast_channel_unlock(caller);
2210  ast_channel_lock(agent);
2211  agent_snapshot = ast_channel_snapshot_create(agent);
2212  ast_channel_unlock(agent);
2213 
2214  if (!caller_snapshot || !agent_snapshot) {
2215  return;
2216  }
2217 
2219  agent_snapshot, type, blob);
2220 }
2221 
2222 /*!
2223  * \internal
2224  * \brief Publish the member blob.
2225  * \since 12.0.0
2226  *
2227  * \param type Stasis message type to publish.
2228  * \param blob The information being published.
2229  *
2230  * \note The json blob reference is passed to this function.
2231  *
2232  * \return Nothing
2233  */
2235 {
2236  RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
2237  RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
2238 
2239  if (!blob || !type) {
2240  ast_json_unref(blob);
2241  return;
2242  }
2243 
2244  payload = ast_json_payload_create(blob);
2245  ast_json_unref(blob);
2246  if (!payload) {
2247  return;
2248  }
2249 
2250  msg = stasis_message_create(type, payload);
2251  if (!msg) {
2252  return;
2253  }
2254 
2256 }
2257 
2258 static struct ast_json *queue_member_blob_create(struct call_queue *q, struct member *mem)
2259 {
2260  return ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: i, s: i, s: i, s: i, s: i, s: i, s: i, s: s, s: i, s: i}",
2261  "Queue", q->name,
2262  "MemberName", mem->membername,
2263  "Interface", mem->interface,
2264  "StateInterface", mem->state_interface,
2265  "Membership", (mem->dynamic ? "dynamic" : (mem->realtime ? "realtime" : "static")),
2266  "Penalty", mem->penalty,
2267  "CallsTaken", mem->calls,
2268  "LastCall", (int)mem->lastcall,
2269  "LastPause", (int)mem->lastpause,
2270  "InCall", mem->starttime ? 1 : 0,
2271  "Status", mem->status,
2272  "Paused", mem->paused,
2273  "PausedReason", mem->reason_paused,
2274  "Ringinuse", mem->ringinuse,
2275  "Wrapuptime", mem->wrapuptime);
2276 }
2277 
2278 /*! \brief Check if members are available
2279  *
2280  * This function checks to see if members are available to be called. If any member
2281  * is available, the function immediately returns 0. If no members are available,
2282  * then -1 is returned.
2283  */
2284 static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, int raise_penalty, enum empty_conditions conditions, int devstate)
2285 {
2286  struct member *member;
2287  struct ao2_iterator mem_iter;
2288 
2289  ao2_lock(q);
2290  mem_iter = ao2_iterator_init(q->members, 0);
2291  for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
2292  int penalty = member->penalty;
2293  if (raise_penalty != INT_MAX && penalty < raise_penalty) {
2294  ast_debug(4, "%s is having his penalty raised up from %d to %d\n", member->membername, penalty, raise_penalty);
2295  penalty = raise_penalty;
2296  }
2297  if ((max_penalty != INT_MAX && penalty > max_penalty) || (min_penalty != INT_MAX && penalty < min_penalty)) {
2298  if (conditions & QUEUE_EMPTY_PENALTY) {
2299  ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
2300  continue;
2301  }
2302  }
2303 
2304  switch (devstate ? ast_device_state(member->state_interface) : member->status) {
2305  case AST_DEVICE_INVALID:
2306  if (conditions & QUEUE_EMPTY_INVALID) {
2307  ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername);
2308  break;
2309  }
2310  goto default_case;
2312  if (conditions & QUEUE_EMPTY_UNAVAILABLE) {
2313  ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername);
2314  break;
2315  }
2316  goto default_case;
2317  case AST_DEVICE_INUSE:
2318  if (conditions & QUEUE_EMPTY_INUSE) {
2319  ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername);
2320  break;
2321  }
2322  goto default_case;
2323  case AST_DEVICE_RINGING:
2324  if (conditions & QUEUE_EMPTY_RINGING) {
2325  ast_debug(4, "%s is unavailable because his device state is 'ringing'\n", member->membername);
2326  break;
2327  }
2328  goto default_case;
2329  case AST_DEVICE_UNKNOWN:
2330  if (conditions & QUEUE_EMPTY_UNKNOWN) {
2331  ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername);
2332  break;
2333  }
2334  /* Fall-through */
2335  default:
2336  default_case:
2337  if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) {
2338  ast_debug(4, "%s is unavailable because he is paused'\n", member->membername);
2339  break;
2340  } else if ((conditions & QUEUE_EMPTY_WRAPUP)
2341  && member->lastcall
2342  && get_wrapuptime(q, member)
2343  && (time(NULL) - get_wrapuptime(q, member) < member->lastcall)) {
2344  ast_debug(4, "%s is unavailable because it has only been %d seconds since his last call (wrapup time is %d)\n",
2345  member->membername, (int) (time(NULL) - member->lastcall), get_wrapuptime(q, member));
2346  break;
2347  } else {
2348  ao2_ref(member, -1);
2349  ao2_iterator_destroy(&mem_iter);
2350  ao2_unlock(q);
2351  ast_debug(4, "%s is available.\n", member->membername);
2352  return 0;
2353  }
2354  break;
2355  }
2356  }
2357  ao2_iterator_destroy(&mem_iter);
2358  ao2_unlock(q);
2359 
2360  if (!devstate && (conditions & QUEUE_EMPTY_RINGING)) {
2361  /* member state still may be RINGING due to lag in event message - check again with device state */
2362  return get_member_status(q, max_penalty, min_penalty, raise_penalty, conditions, 1);
2363  }
2364  return -1;
2365 }
2366 
2367 /*
2368  * A "pool" of member objects that calls are currently pending on. If an
2369  * agent is a member of multiple queues it's possible for that agent to be
2370  * called by each of the queues at the same time. This happens because device
2371  * state is slow to notify the queue app of one of it's member's being rung.
2372  * This "pool" allows us to track which members are currently being rung while
2373  * we wait on the device state change.
2374  */
2376 #define MAX_CALL_ATTEMPT_BUCKETS 353
2377 
2378 static int pending_members_hash(const void *obj, const int flags)
2379 {
2380  const struct member *object;
2381  const char *key;
2382 
2383  switch (flags & OBJ_SEARCH_MASK) {
2384  case OBJ_SEARCH_KEY:
2385  key = obj;
2386  break;
2387  case OBJ_SEARCH_OBJECT:
2388  object = obj;
2389  key = object->interface;
2390  break;
2391  default:
2392  ast_assert(0);
2393  return 0;
2394  }
2395  return ast_str_case_hash(key);
2396 }
2397 
2398 static int pending_members_cmp(void *obj, void *arg, int flags)
2399 {
2400  const struct member *object_left = obj;
2401  const struct member *object_right = arg;
2402  const char *right_key = arg;
2403  int cmp;
2404 
2405  switch (flags & OBJ_SEARCH_MASK) {
2406  case OBJ_SEARCH_OBJECT:
2407  right_key = object_right->interface;
2408  /* Fall through */
2409  case OBJ_SEARCH_KEY:
2410  cmp = strcasecmp(object_left->interface, right_key);
2411  break;
2413  /* Not supported by container. */
2414  ast_assert(0);
2415  return 0;
2416  default:
2417  cmp = 0;
2418  break;
2419  }
2420  if (cmp) {
2421  return 0;
2422  }
2423  return CMP_MATCH;
2424 }
2425 
2426 static void pending_members_remove(struct member *mem)
2427 {
2428  ast_debug(3, "Removed %s from pending_members\n", mem->membername);
2429  ao2_find(pending_members, mem, OBJ_POINTER | OBJ_NODATA | OBJ_UNLINK);
2430 }
2431 
2432 /*! \brief set a member's status based on device state of that member's state_interface.
2433  *
2434  * Lock interface list find sc, iterate through each queues queue_member list for member to
2435  * update state inside queues
2436 */
2437 static void update_status(struct call_queue *q, struct member *m, const int status)
2438 {
2439  if (m->status != status) {
2440  /* If this member has transitioned to being available then update their queue
2441  * information. If they are currently in a call then the leg to the agent will be
2442  * considered done and the call finished.
2443  */
2444  if (status == AST_DEVICE_NOT_INUSE) {
2446  }
2447 
2448  m->status = status;
2449 
2450  /* Remove the member from the pending members pool only when the status changes.
2451  * This is not done unconditionally because we can occasionally see multiple
2452  * device state notifications of not in use after a previous call has ended,
2453  * including after we have initiated a new call. This is more likely to
2454  * happen when there is latency in the connection to the member.
2455  */
2457 
2458  queue_publish_member_blob(queue_member_status_type(), queue_member_blob_create(q, m));
2459  }
2460 }
2461 
2462 /*!
2463  * \internal
2464  * \brief Determine if a queue member is available
2465  * \retval 1 if the member is available
2466  * \retval 0 if the member is not available
2467  */
2468 static int is_member_available(struct call_queue *q, struct member *mem)
2469 {
2470  int available = 0;
2471  int wrapuptime;
2472 
2473  switch (mem->status) {
2474  case AST_DEVICE_INVALID:
2476  break;
2477  case AST_DEVICE_INUSE:
2478  case AST_DEVICE_BUSY:
2479  case AST_DEVICE_RINGING:
2480  case AST_DEVICE_RINGINUSE:
2481  case AST_DEVICE_ONHOLD:
2482  if (!mem->ringinuse) {
2483  break;
2484  }
2485  /* else fall through */
2486  case AST_DEVICE_NOT_INUSE:
2487  case AST_DEVICE_UNKNOWN:
2488  if (!mem->paused) {
2489  available = 1;
2490  }
2491  break;
2492  }
2493 
2494  /* Let wrapuptimes override device state availability */
2495  wrapuptime = get_wrapuptime(q, mem);
2496  if (mem->lastcall && wrapuptime && (time(NULL) - wrapuptime < mem->lastcall)) {
2497  available = 0;
2498  }
2499  return available;
2500 }
2501 
2502 /*! \brief set a member's status based on device state of that member's interface*/
2503 static void device_state_cb(void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
2504 {
2505  struct ao2_iterator miter, qiter;
2506  struct ast_device_state_message *dev_state;
2507  struct member *m;
2508  struct call_queue *q;
2509  char interface[80], *slash_pos;
2510  int found = 0; /* Found this member in any queue */
2511  int found_member; /* Found this member in this queue */
2512  int avail = 0; /* Found an available member in this queue */
2513 
2515  return;
2516  }
2517 
2518  dev_state = stasis_message_data(msg);
2519  if (dev_state->eid) {
2520  /* ignore non-aggregate states */
2521  return;
2522  }
2523 
2524  qiter = ao2_iterator_init(queues, 0);
2525  while ((q = ao2_t_iterator_next(&qiter, "Iterate over queues"))) {
2526  ao2_lock(q);
2527 
2528  avail = 0;
2529  found_member = 0;
2530  miter = ao2_iterator_init(q->members, 0);
2531  for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
2532  if (!found_member) {
2533  ast_copy_string(interface, m->state_interface, sizeof(interface));
2534 
2535  if ((slash_pos = strchr(interface, '/'))) {
2536  if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/'))) {
2537  *slash_pos = '\0';
2538  }
2539  }
2540 
2541  if (!strcasecmp(interface, dev_state->device)) {
2542  found_member = 1;
2543  update_status(q, m, dev_state->state);
2544  }
2545  }
2546 
2547  /* check every member until we find one NOT_INUSE */
2548  if (!avail) {
2549  avail = is_member_available(q, m);
2550  }
2551  if (avail && found_member) {
2552  /* early exit as we've found an available member and the member of interest */
2553  ao2_ref(m, -1);
2554  break;
2555  }
2556  }
2557 
2558  if (found_member) {
2559  found = 1;
2560  if (avail) {
2562  } else {
2564  }
2565  }
2566 
2567  ao2_iterator_destroy(&miter);
2568 
2569  ao2_unlock(q);
2570  queue_t_unref(q, "Done with iterator");
2571  }
2572  ao2_iterator_destroy(&qiter);
2573 
2574  if (found) {
2575  ast_debug(1, "Device '%s' changed to state '%u' (%s)\n",
2576  dev_state->device,
2577  dev_state->state,
2578  ast_devstate2str(dev_state->state));
2579  } else {
2580  ast_debug(3, "Device '%s' changed to state '%u' (%s) but we don't care because they're not a member of any queue.\n",
2581  dev_state->device,
2582  dev_state->state,
2583  ast_devstate2str(dev_state->state));
2584  }
2585 
2586  return;
2587 }
2588 
2589 /*! \brief Helper function which converts from extension state to device state values */
2591 {
2592  switch (state) {
2594  state = AST_DEVICE_NOT_INUSE;
2595  break;
2596  case AST_EXTENSION_INUSE:
2597  state = AST_DEVICE_INUSE;
2598  break;
2599  case AST_EXTENSION_BUSY:
2600  state = AST_DEVICE_BUSY;
2601  break;
2602  case AST_EXTENSION_RINGING:
2603  state = AST_DEVICE_RINGING;
2604  break;
2606  state = AST_DEVICE_RINGINUSE;
2607  break;
2608  case AST_EXTENSION_ONHOLD:
2609  state = AST_DEVICE_ONHOLD;
2610  break;
2612  state = AST_DEVICE_INUSE;
2613  break;
2615  state = AST_DEVICE_UNAVAILABLE;
2616  break;
2617  case AST_EXTENSION_REMOVED:
2619  default:
2620  state = AST_DEVICE_INVALID;
2621  break;
2622  }
2623 
2624  return state;
2625 }
2626 
2627 static int extension_state_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
2628 {
2629  struct ao2_iterator miter, qiter;
2630  struct member *m;
2631  struct call_queue *q;
2632  int state = info->exten_state;
2633  int found = 0, device_state = extensionstate2devicestate(state);
2634 
2635  /* only interested in extension state updates involving device states */
2636  if (info->reason != AST_HINT_UPDATE_DEVICE) {
2637  return 0;
2638  }
2639 
2640  qiter = ao2_iterator_init(queues, 0);
2641  while ((q = ao2_t_iterator_next(&qiter, "Iterate through queues"))) {
2642  ao2_lock(q);
2643 
2644  miter = ao2_iterator_init(q->members, 0);
2645  for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
2646  if (!strcmp(m->state_context, context) && !strcmp(m->state_exten, exten)) {
2647  update_status(q, m, device_state);
2648  ao2_ref(m, -1);
2649  found = 1;
2650  break;
2651  }
2652  }
2653  ao2_iterator_destroy(&miter);
2654 
2655  ao2_unlock(q);
2656  queue_t_unref(q, "Done with iterator");
2657  }
2658  ao2_iterator_destroy(&qiter);
2659 
2660  if (found) {
2661  ast_debug(1, "Extension '%s@%s' changed to state '%d' (%s)\n", exten, context, device_state, ast_devstate2str(device_state));
2662  } else {
2663  ast_debug(3, "Extension '%s@%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n",
2664  exten, context, device_state, ast_devstate2str(device_state));
2665  }
2666 
2667  return 0;
2668 }
2669 
2670 /*! \brief Return the current state of a member */
2671 static int get_queue_member_status(struct member *cur)
2672 {
2674 }
2675 
2676 static void destroy_queue_member_cb(void *obj)
2677 {
2678  struct member *mem = obj;
2679 
2680  if (mem->state_id != -1) {
2682  }
2683 }
2684 
2685 /*! \brief allocate space for new queue member and set fields based on parameters passed */
2686 static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface, int ringinuse, int wrapuptime)
2687 {
2688  struct member *cur;
2689 
2690  if ((cur = ao2_alloc(sizeof(*cur), destroy_queue_member_cb))) {
2691  cur->ringinuse = ringinuse;
2692  cur->penalty = penalty;
2693  cur->paused = paused;
2694  cur->wrapuptime = wrapuptime;
2695  if (paused) {
2696  time(&cur->lastpause); /* Update time of last pause */
2697  }
2698  ast_copy_string(cur->interface, interface, sizeof(cur->interface));
2699  if (!ast_strlen_zero(state_interface)) {
2700  ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface));
2701  } else {
2702  ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface));
2703  }
2704  if (!ast_strlen_zero(membername)) {
2705  ast_copy_string(cur->membername, membername, sizeof(cur->membername));
2706  } else {
2707  ast_copy_string(cur->membername, interface, sizeof(cur->membername));
2708  }
2709  if (!strchr(cur->interface, '/')) {
2710  ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
2711  }
2712  if (!strncmp(cur->state_interface, "hint:", 5)) {
2713  char *tmp = ast_strdupa(cur->state_interface), *context = tmp;
2714  char *exten = strsep(&context, "@") + 5;
2715 
2716  ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten));
2717  ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context));
2718 
2720  } else {
2721  cur->state_id = -1;
2722  }
2723  cur->status = get_queue_member_status(cur);
2724  }
2725 
2726  return cur;
2727 }
2728 
2729 
2730 static int compress_char(const char c)
2731 {
2732  if (c < 32) {
2733  return 0;
2734  } else if (c > 96) {
2735  return c - 64;
2736  }
2737  return c - 32;
2738 }
2739 
2740 static int member_hash_fn(const void *obj, const int flags)
2741 {
2742  const struct member *mem = obj;
2743  const char *interface = (flags & OBJ_KEY) ? obj : mem->interface;
2744  const char *chname = strchr(interface, '/');
2745  int ret = 0, i;
2746 
2747  if (!chname) {
2748  chname = interface;
2749  }
2750  for (i = 0; i < 5 && chname[i]; i++) {
2751  ret += compress_char(chname[i]) << (i * 6);
2752  }
2753  return ret;
2754 }
2755 
2756 static int member_cmp_fn(void *obj1, void *obj2, int flags)
2757 {
2758  struct member *mem1 = obj1;
2759  struct member *mem2 = obj2;
2760  const char *interface = (flags & OBJ_KEY) ? obj2 : mem2->interface;
2761 
2762  return strcasecmp(mem1->interface, interface) ? 0 : CMP_MATCH | CMP_STOP;
2763 }
2764 
2765 /*!
2766  * \brief Initialize Queue default values.
2767  * \note the queue's lock must be held before executing this function
2768 */
2769 static void init_queue(struct call_queue *q)
2770 {
2771  int i;
2772  struct penalty_rule *pr_iter;
2773 
2774  q->dead = 0;
2775  q->retry = DEFAULT_RETRY;
2776  q->timeout = DEFAULT_TIMEOUT;
2777  q->maxlen = 0;
2778 
2779  ast_string_field_set(q, context, "");
2780 
2781  q->announcefrequency = 0;
2783  q->announceholdtime = 1;
2784  q->announceposition_only_up = 0;
2785  q->announcepositionlimit = 10; /* Default 10 positions */
2786  q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */
2787  q->roundingseconds = 0; /* Default - don't announce seconds */
2788  q->servicelevel = 0;
2789  q->ringinuse = 1;
2790  q->announce_to_first_user = 0;
2791  q->setinterfacevar = 0;
2792  q->setqueuevar = 0;
2793  q->setqueueentryvar = 0;
2795  q->montype = montype_default;
2796  q->monfmt[0] = '\0';
2797  q->reportholdtime = 0;
2798  q->wrapuptime = 0;
2799  q->penaltymemberslimit = 0;
2800  q->joinempty = 0;
2801  q->leavewhenempty = 0;
2802  q->memberdelay = 0;
2803  q->weight = 0;
2804  q->timeoutrestart = 0;
2806  q->randomperiodicannounce = 0;
2807  q->numperiodicannounce = 0;
2810  q->autopausedelay = 0;
2811  if (!q->members) {
2813  /* linear strategy depends on order, so we have to place all members in a list */
2815  } else {
2818  }
2819  }
2820  q->found = 1;
2821 
2822  ast_string_field_set(q, moh, "");
2823  ast_string_field_set(q, sound_next, "queue-youarenext");
2824  ast_string_field_set(q, sound_thereare, "queue-thereare");
2825  ast_string_field_set(q, sound_calls, "queue-callswaiting");
2826  ast_string_field_set(q, queue_quantity1, "queue-quantity1");
2827  ast_string_field_set(q, queue_quantity2, "queue-quantity2");
2828  ast_string_field_set(q, sound_holdtime, "queue-holdtime");
2829  ast_string_field_set(q, sound_minutes, "queue-minutes");
2830  ast_string_field_set(q, sound_minute, "queue-minute");
2831  ast_string_field_set(q, sound_seconds, "queue-seconds");
2832  ast_string_field_set(q, sound_thanks, "queue-thankyou");
2833  ast_string_field_set(q, sound_reporthold, "queue-reporthold");
2834 
2835  if (!q->sound_periodicannounce[0]) {
2837  }
2838 
2839  if (q->sound_periodicannounce[0]) {
2840  ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
2841  }
2842 
2843  for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
2844  if (q->sound_periodicannounce[i]) {
2845  ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
2846  }
2847  }
2848 
2849  while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list))) {
2850  ast_free(pr_iter);
2851  }
2852 
2853  /* On restart assume no members are available.
2854  * The queue_avail hint is a boolean state to indicate whether a member is available or not.
2855  *
2856  * This seems counter intuitive, but is required to light a BLF
2857  * AST_DEVICE_INUSE indicates no members are available.
2858  * AST_DEVICE_NOT_INUSE indicates a member is available.
2859  */
2861 }
2862 
2863 static void clear_queue(struct call_queue *q)
2864 {
2865  q->holdtime = 0;
2866  q->callscompleted = 0;
2867  q->callsabandoned = 0;
2868  q->callscompletedinsl = 0;
2869  q->callsabandonedinsl = 0;
2870  q->talktime = 0;
2871 
2872  if (q->members) {
2873  struct member *mem;
2874  struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
2875  while ((mem = ao2_iterator_next(&mem_iter))) {
2876  mem->calls = 0;
2877  mem->callcompletedinsl = 0;
2878  mem->lastcall = 0;
2879  mem->starttime = 0;
2880  ao2_ref(mem, -1);
2881  }
2882  ao2_iterator_destroy(&mem_iter);
2883  }
2884 }
2885 
2886 /*!
2887  * \brief Change queue penalty by adding rule.
2888  *
2889  * Check rule for errors with time or fomatting, see if rule is relative to rest
2890  * of queue, iterate list of rules to find correct insertion point, insert and return.
2891  * \retval -1 on failure
2892  * \retval 0 on success
2893  * \note Call this with the rule_lists locked
2894 */
2895 static int insert_penaltychange(const char *list_name, const char *content, const int linenum)
2896 {
2897  char *timestr, *maxstr, *minstr, *raisestr, *contentdup;
2898  struct penalty_rule *rule = NULL, *rule_iter;
2899  struct rule_list *rl_iter;
2900  int penaltychangetime, inserted = 0;
2901 
2902  if (!(rule = ast_calloc(1, sizeof(*rule)))) {
2903  return -1;
2904  }
2905 
2906  contentdup = ast_strdupa(content);
2907 
2908  if (!(maxstr = strchr(contentdup, ','))) {
2909  ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum);
2910  ast_free(rule);
2911  return -1;
2912  }
2913 
2914  *maxstr++ = '\0';
2915  if ((minstr = strchr(maxstr,','))) {
2916  *minstr++ = '\0';
2917  if ((raisestr = strchr(minstr,','))) {
2918  *raisestr++ = '\0';
2919  }
2920  } else {
2921  raisestr = NULL;
2922  }
2923 
2924  timestr = contentdup;
2925  if ((penaltychangetime = atoi(timestr)) < 0) {
2926  ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum);
2927  ast_free(rule);
2928  return -1;
2929  }
2930 
2931  rule->time = penaltychangetime;
2932 
2933  /* The last check will evaluate true if either no penalty change is indicated for a given rule
2934  * OR if a min penalty change is indicated but no max penalty change is */
2935  if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') {
2936  rule->max_relative = 1;
2937  }
2938 
2939  rule->max_value = atoi(maxstr);
2940 
2941  if (!ast_strlen_zero(minstr)) {
2942  if (*minstr == '+' || *minstr == '-') {
2943  rule->min_relative = 1;
2944  }
2945  rule->min_value = atoi(minstr);
2946  } else { /*there was no minimum specified, so assume this means no change*/
2947  rule->min_relative = 1;
2948  }
2949 
2950  if (!ast_strlen_zero(raisestr)) {
2951  if (*raisestr == '+' || *raisestr == '-') {
2952  rule->raise_relative = 1;
2953  }
2954  rule->raise_value = atoi(raisestr);
2955  } else { /*there was no raise specified, so assume this means no change*/
2956  rule->raise_relative = 1;
2957  }
2958 
2959  /*We have the rule made, now we need to insert it where it belongs*/
2960  AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){
2961  if (strcasecmp(rl_iter->name, list_name)) {
2962  continue;
2963  }
2964 
2965  AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) {
2966  if (rule->time < rule_iter->time) {
2968  inserted = 1;
2969  break;
2970  }
2971  }
2973 
2974  if (!inserted) {
2975  AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list);
2976  inserted = 1;
2977  }
2978 
2979  break;
2980  }
2981 
2982  if (!inserted) {
2983  ast_log(LOG_WARNING, "Unknown rule list name %s; ignoring.\n", list_name);
2984  ast_free(rule);
2985  return -1;
2986  }
2987  return 0;
2988 }
2989 
2990 /*!
2991  * \brief Load queue rules from realtime.
2992  *
2993  * Check rule for errors with time or fomatting, see if rule is relative to rest
2994  * of queue, iterate list of rules to find correct insertion point, insert and return.
2995  * \retval -1 on failure
2996  * \retval 0 on success
2997  * \note Call this with the rule_lists locked
2998 */
2999 static int load_realtime_rules(void)
3000 {
3001  struct ast_config *cfg;
3002  struct rule_list *rl_iter, *new_rl;
3003  struct penalty_rule *pr_iter;
3004  char *rulecat = NULL;
3005 
3006  if (!ast_check_realtime("queue_rules")) {
3007  ast_log(LOG_WARNING, "Missing \"queue_rules\" in extconfig.conf\n");
3008  return 0;
3009  }
3010  if (!(cfg = ast_load_realtime_multientry("queue_rules", "rule_name LIKE", "%", SENTINEL))) {
3011  ast_log(LOG_WARNING, "Failed to load queue rules from realtime\n");
3012  return 0;
3013  }
3014  while ((rulecat = ast_category_browse(cfg, rulecat))) {
3015  const char *timestr, *maxstr, *minstr, *raisestr, *rule_name;
3016  int penaltychangetime, rule_exists = 0, inserted = 0;
3017  int max_penalty = 0, min_penalty = 0, raise_penalty = 0;
3018  int min_relative = 0, max_relative = 0, raise_relative = 0;
3019  struct penalty_rule *new_penalty_rule = NULL;
3020 
3021  rule_name = ast_variable_retrieve(cfg, rulecat, "rule_name");
3022  if (ast_strlen_zero(rule_name)) {
3023  continue;
3024  }
3025 
3026  AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
3027  if (!(strcasecmp(rl_iter->name, rule_name))) {
3028  rule_exists = 1;
3029  new_rl = rl_iter;
3030  break;
3031  }
3032  }
3033  if (!rule_exists) {
3034  if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
3035  ast_config_destroy(cfg);
3036  return -1;
3037  }
3038  ast_copy_string(new_rl->name, rule_name, sizeof(new_rl->name));
3040  }
3041  timestr = ast_variable_retrieve(cfg, rulecat, "time");
3042  if (!(timestr) || sscanf(timestr, "%30d", &penaltychangetime) != 1) {
3043  ast_log(LOG_NOTICE, "Failed to parse time (%s) for one of the %s rules, skipping it\n",
3044  (ast_strlen_zero(timestr) ? "invalid value" : timestr), rule_name);
3045  continue;
3046  }
3047  if (!(new_penalty_rule = ast_calloc(1, sizeof(*new_penalty_rule)))) {
3048  ast_config_destroy(cfg);
3049  return -1;
3050  }
3051  if (!(maxstr = ast_variable_retrieve(cfg, rulecat, "max_penalty")) ||
3052  ast_strlen_zero(maxstr) || sscanf(maxstr, "%30d", &max_penalty) != 1) {
3053  max_penalty = 0;
3054  max_relative = 1;
3055  } else {
3056  if (*maxstr == '+' || *maxstr == '-') {
3057  max_relative = 1;
3058  }
3059  }
3060  if (!(minstr = ast_variable_retrieve(cfg, rulecat, "min_penalty")) ||
3061  ast_strlen_zero(minstr) || sscanf(minstr, "%30d", &min_penalty) != 1) {
3062  min_penalty = 0;
3063  min_relative = 1;
3064  } else {
3065  if (*minstr == '+' || *minstr == '-') {
3066  min_relative = 1;
3067  }
3068  }
3069  if (!(raisestr = ast_variable_retrieve(cfg, rulecat, "raise_penalty")) ||
3070  ast_strlen_zero(raisestr) || sscanf(raisestr, "%30d", &raise_penalty) != 1) {
3071  raise_penalty = 0;
3072  raise_relative = 1;
3073  } else {
3074  if (*raisestr == '+' || *raisestr == '-') {
3075  raise_relative = 1;
3076  }
3077  }
3078  new_penalty_rule->time = penaltychangetime;
3079  new_penalty_rule->max_relative = max_relative;
3080  new_penalty_rule->max_value = max_penalty;
3081  new_penalty_rule->min_relative = min_relative;
3082  new_penalty_rule->min_value = min_penalty;
3083  new_penalty_rule->raise_relative = raise_relative;
3084  new_penalty_rule->raise_value = raise_penalty;
3085  AST_LIST_TRAVERSE_SAFE_BEGIN(&new_rl->rules, pr_iter, list) {
3086  if (new_penalty_rule->time < pr_iter->time) {
3087  AST_LIST_INSERT_BEFORE_CURRENT(new_penalty_rule, list);
3088  inserted = 1;
3089  }
3090  }
3092  if (!inserted) {
3093  AST_LIST_INSERT_TAIL(&new_rl->rules, new_penalty_rule, list);
3094  }
3095  }
3096 
3097  ast_config_destroy(cfg);
3098  return 0;
3099 }
3100 
3101 static void parse_empty_options(const char *value, enum empty_conditions *empty, int joinempty)
3102 {
3103  char *value_copy = ast_strdupa(value);
3104  char *option = NULL;
3105  while ((option = strsep(&value_copy, ","))) {
3106  if (!strcasecmp(option, "paused")) {
3107  *empty |= QUEUE_EMPTY_PAUSED;
3108  } else if (!strcasecmp(option, "penalty")) {
3109  *empty |= QUEUE_EMPTY_PENALTY;
3110  } else if (!strcasecmp(option, "inuse")) {
3111  *empty |= QUEUE_EMPTY_INUSE;
3112  } else if (!strcasecmp(option, "ringing")) {
3113  *empty |= QUEUE_EMPTY_RINGING;
3114  } else if (!strcasecmp(option, "invalid")) {
3115  *empty |= QUEUE_EMPTY_INVALID;
3116  } else if (!strcasecmp(option, "wrapup")) {
3117  *empty |= QUEUE_EMPTY_WRAPUP;
3118  } else if (!strcasecmp(option, "unavailable")) {
3119  *empty |= QUEUE_EMPTY_UNAVAILABLE;
3120  } else if (!strcasecmp(option, "unknown")) {
3121  *empty |= QUEUE_EMPTY_UNKNOWN;
3122  } else if (!strcasecmp(option, "loose")) {
3124  } else if (!strcasecmp(option, "strict")) {
3126  } else if ((ast_false(option) && joinempty) || (ast_true(option) && !joinempty)) {
3128  } else if ((ast_false(option) && !joinempty) || (ast_true(option) && joinempty)) {
3129  *empty = 0;
3130  } else {
3131  ast_log(LOG_WARNING, "Unknown option %s for '%s'\n", option, joinempty ? "joinempty" : "leavewhenempty");
3132  }
3133  }
3134 }
3135 
3136 /*! \brief Configure a queue parameter.
3137  *
3138  * The failunknown flag is set for config files (and static realtime) to show
3139  * errors for unknown parameters. It is cleared for dynamic realtime to allow
3140  * extra fields in the tables.
3141  * \note For error reporting, line number is passed for .conf static configuration,
3142  * for Realtime queues, linenum is -1.
3143 */
3144 static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
3145 {
3146  if (!strcasecmp(param, "musicclass") ||
3147  !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
3148  ast_string_field_set(q, moh, val);
3149  } else if (!strcasecmp(param, "announce")) {
3150  ast_string_field_set(q, announce, val);
3151  } else if (!strcasecmp(param, "context")) {
3152  ast_string_field_set(q, context, val);
3153  } else if (!strcasecmp(param, "timeout")) {
3154  q->timeout = atoi(val);
3155  if (q->timeout < 0) {
3156  q->timeout = DEFAULT_TIMEOUT;
3157  }
3158  } else if (!strcasecmp(param, "ringinuse")) {
3159  q->ringinuse = ast_true(val);
3160  } else if (!strcasecmp(param, "setinterfacevar")) {
3161  q->setinterfacevar = ast_true(val);
3162  } else if (!strcasecmp(param, "setqueuevar")) {
3163  q->setqueuevar = ast_true(val);
3164  } else if (!strcasecmp(param, "setqueueentryvar")) {
3165  q->setqueueentryvar = ast_true(val);
3166  } else if (!strcasecmp(param, "monitor-format")) {
3167  ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
3168  } else if (!strcasecmp(param, "membermacro")) {
3169  ast_string_field_set(q, membermacro, val);
3170  } else if (!strcasecmp(param, "membergosub")) {
3171  ast_string_field_set(q, membergosub, val);
3172  } else if (!strcasecmp(param, "queue-youarenext")) {
3173  ast_string_field_set(q, sound_next, val);
3174  } else if (!strcasecmp(param, "queue-thereare")) {
3175  ast_string_field_set(q, sound_thereare, val);
3176  } else if (!strcasecmp(param, "queue-callswaiting")) {
3177  ast_string_field_set(q, sound_calls, val);
3178  } else if (!strcasecmp(param, "queue-quantity1")) {
3179  ast_string_field_set(q, queue_quantity1, val);
3180  } else if (!strcasecmp(param, "queue-quantity2")) {
3181  ast_string_field_set(q, queue_quantity2, val);
3182  } else if (!strcasecmp(param, "queue-holdtime")) {
3183  ast_string_field_set(q, sound_holdtime, val);
3184  } else if (!strcasecmp(param, "queue-minutes")) {
3185  ast_string_field_set(q, sound_minutes, val);
3186  } else if (!strcasecmp(param, "queue-minute")) {
3187  ast_string_field_set(q, sound_minute, val);
3188  } else if (!strcasecmp(param, "queue-seconds")) {
3189  ast_string_field_set(q, sound_seconds, val);
3190  } else if (!strcasecmp(param, "queue-thankyou")) {
3191  ast_string_field_set(q, sound_thanks, val);
3192  } else if (!strcasecmp(param, "queue-callerannounce")) {
3193  ast_string_field_set(q, sound_callerannounce, val);
3194  } else if (!strcasecmp(param, "queue-reporthold")) {
3195  ast_string_field_set(q, sound_reporthold, val);
3196  } else if (!strcasecmp(param, "announce-frequency")) {
3197  q->announcefrequency = atoi(val);
3198  } else if (!strcasecmp(param, "announce-to-first-user")) {
3199  q->announce_to_first_user = ast_true(val);
3200  } else if (!strcasecmp(param, "min-announce-frequency")) {
3201  q->minannouncefrequency = atoi(val);
3202  ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name);
3203  } else if (!strcasecmp(param, "announce-round-seconds")) {
3204  q->roundingseconds = atoi(val);
3205  /* Rounding to any other values just doesn't make sense... */
3206  if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10
3207  || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) {
3208  if (linenum >= 0) {
3209  ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
3210  "using 0 instead for queue '%s' at line %d of queues.conf\n",
3211  val, param, q->name, linenum);
3212  } else {
3213  ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
3214  "using 0 instead for queue '%s'\n", val, param, q->name);
3215  }
3216  q->roundingseconds=0;
3217  }
3218  } else if (!strcasecmp(param, "announce-holdtime")) {
3219  if (!strcasecmp(val, "once")) {
3221  } else if (ast_true(val)) {
3223  } else {
3224  q->announceholdtime = 0;
3225  }
3226  } else if (!strcasecmp(param, "announce-position")) {
3227  if (!strcasecmp(val, "limit")) {
3229  } else if (!strcasecmp(val, "more")) {
3231  } else if (ast_true(val)) {
3233  } else {
3235  }
3236  } else if (!strcasecmp(param, "announce-position-only-up")) {
3238  } else if (!strcasecmp(param, "announce-position-limit")) {
3239  q->announcepositionlimit = atoi(val);
3240  } else if (!strcasecmp(param, "periodic-announce")) {
3241  if (strchr(val, ',')) {
3242  char *s, *buf = ast_strdupa(val);
3243  unsigned int i = 0;
3244 
3245  while ((s = strsep(&buf, ",|"))) {
3246  if (!q->sound_periodicannounce[i]) {
3248  }
3249  ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s);
3250  i++;
3251  if (i == MAX_PERIODIC_ANNOUNCEMENTS) {
3252  break;
3253  }
3254  }
3255  q->numperiodicannounce = i;
3256  } else {
3257  ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val);
3258  q->numperiodicannounce = 1;
3259  }
3260  } else if (!strcasecmp(param, "periodic-announce-frequency")) {
3261  q->periodicannouncefrequency = atoi(val);
3262  } else if (!strcasecmp(param, "relative-periodic-announce")) {
3264  } else if (!strcasecmp(param, "random-periodic-announce")) {
3265  q->randomperiodicannounce = ast_true(val);
3266  } else if (!strcasecmp(param, "retry")) {
3267  q->retry = atoi(val);
3268  if (q->retry <= 0) {
3269  q->retry = DEFAULT_RETRY;
3270  }
3271  } else if (!strcasecmp(param, "wrapuptime")) {
3272  q->wrapuptime = atoi(val);
3273  } else if (!strcasecmp(param, "penaltymemberslimit")) {
3274  if ((sscanf(val, "%10d", &q->penaltymemberslimit) != 1)) {
3275  q->penaltymemberslimit = 0;
3276  }
3277  } else if (!strcasecmp(param, "autofill")) {
3278  q->autofill = ast_true(val);
3279  } else if (!strcasecmp(param, "monitor-type")) {
3280  if (!strcasecmp(val, "mixmonitor")) {
3281  q->montype = 1;
3282  }
3283  } else if (!strcasecmp(param, "autopause")) {
3284  q->autopause = autopause2int(val);
3285  } else if (!strcasecmp(param, "autopausedelay")) {
3286  q->autopausedelay = atoi(val);
3287  } else if (!strcasecmp(param, "autopausebusy")) {
3288  q->autopausebusy = ast_true(val);
3289  } else if (!strcasecmp(param, "autopauseunavail")) {
3290  q->autopauseunavail = ast_true(val);
3291  } else if (!strcasecmp(param, "maxlen")) {
3292  q->maxlen = atoi(val);
3293  if (q->maxlen < 0) {
3294  q->maxlen = 0;
3295  }
3296  } else if (!strcasecmp(param, "servicelevel")) {
3297  q->servicelevel= atoi(val);
3298  } else if (!strcasecmp(param, "strategy")) {
3299  int strategy;
3300 
3301  /* We are a static queue and already have set this, no need to do it again */
3302  if (failunknown) {
3303  return;
3304  }
3305  strategy = strat2int(val);
3306  if (strategy < 0) {
3307  ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
3308  val, q->name);
3310  }
3311  if (strategy == q->strategy) {
3312  return;
3313  }
3314  if (strategy == QUEUE_STRATEGY_LINEAR) {
3315  ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n");
3316  return;
3317  }
3318  q->strategy = strategy;
3319  } else if (!strcasecmp(param, "joinempty")) {
3320  parse_empty_options(val, &q->joinempty, 1);
3321  } else if (!strcasecmp(param, "leavewhenempty")) {
3322  parse_empty_options(val, &q->leavewhenempty, 0);
3323  } else if (!strcasecmp(param, "reportholdtime")) {
3324  q->reportholdtime = ast_true(val);
3325  } else if (!strcasecmp(param, "memberdelay")) {
3326  q->memberdelay = atoi(val);
3327  } else if (!strcasecmp(param, "weight")) {
3328  q->weight = atoi(val);
3329  } else if (!strcasecmp(param, "timeoutrestart")) {
3330  q->timeoutrestart = ast_true(val);
3331  } else if (!strcasecmp(param, "defaultrule")) {
3332  ast_string_field_set(q, defaultrule, val);
3333  } else if (!strcasecmp(param, "timeoutpriority")) {
3334  if (!strcasecmp(val, "conf")) {
3336  } else {
3338  }
3339  } else if (failunknown) {
3340  if (linenum >= 0) {
3341  ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
3342  q->name, param, linenum);
3343  } else {
3344  ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
3345  }
3346  }
3347 }
3348 
3349 
3350 #define QUEUE_PAUSED_DEVSTATE AST_DEVICE_INUSE
3351 #define QUEUE_UNPAUSED_DEVSTATE AST_DEVICE_NOT_INUSE
3352 #define QUEUE_UNKNOWN_PAUSED_DEVSTATE AST_DEVICE_NOT_INUSE
3353 
3354 /*! \internal
3355  * \brief If adding a single new member to a queue, use this function instead of ao2_linking.
3356  * This adds round robin queue position data for a fresh member as well as links it.
3357  * \param queue Which queue the member is being added to
3358  * \param mem Which member is being added to the queue
3359  */
3360 static void member_add_to_queue(struct call_queue *queue, struct member *mem)
3361 {
3362  ao2_lock(queue->members);
3363  mem->queuepos = ao2_container_count(queue->members);
3364  ao2_link(queue->members, mem);
3366  AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", queue->name, mem->interface);
3367  ao2_unlock(queue->members);
3368 }
3369 
3370 /*! \internal
3371  * \brief If removing a single member from a queue, use this function instead of ao2_unlinking.
3372  * This will perform round robin queue position reordering for the remaining members.
3373  * \param queue Which queue the member is being removed from
3374  * \param member Which member is being removed from the queue
3375  */
3376 static void member_remove_from_queue(struct call_queue *queue, struct member *mem)
3377 {
3379  ao2_lock(queue->members);
3381  queue_member_follower_removal(queue, mem);
3382  ao2_unlink(queue->members, mem);
3383  ao2_unlock(queue->members);
3384 }
3385 
3386 /*!
3387  * \brief Find rt member record to update otherwise create one.
3388  *
3389  * Search for member in queue, if found update penalty/paused state,
3390  * if no member exists create one flag it as a RT member and add to queue member list.
3391 */
3392 static void rt_handle_member_record(struct call_queue *q, char *category, struct ast_config *member_config)
3393 {
3394  struct member *m;
3395  struct ao2_iterator mem_iter;
3396  int penalty = 0;
3397  int paused = 0;
3398  int found = 0;
3399  int wrapuptime = 0;
3400  int ringinuse = q->ringinuse;
3401 
3402  const char *config_val;
3403  const char *interface = ast_variable_retrieve(member_config, category, "interface");
3404  const char *rt_uniqueid = ast_variable_retrieve(member_config, category, "uniqueid");
3405  const char *membername = S_OR(ast_variable_retrieve(member_config, category, "membername"), interface);
3406  const char *state_interface = S_OR(ast_variable_retrieve(member_config, category, "state_interface"), interface);
3407  const char *penalty_str = ast_variable_retrieve(member_config, category, "penalty");
3408  const char *paused_str = ast_variable_retrieve(member_config, category, "paused");
3409  const char *wrapuptime_str = ast_variable_retrieve(member_config, category, "wrapuptime");
3410 
3411  if (ast_strlen_zero(rt_uniqueid)) {
3412  ast_log(LOG_WARNING, "Realtime field 'uniqueid' is empty for member %s\n",
3413  S_OR(membername, "NULL"));
3414  return;
3415  }
3416 
3417  if (ast_strlen_zero(interface)) {
3418  ast_log(LOG_WARNING, "Realtime field 'interface' is empty for member %s\n",
3419  S_OR(membername, "NULL"));
3420  return;
3421  }
3422 
3423  if (penalty_str) {
3424  penalty = atoi(penalty_str);
3425  if ((penalty < 0) && negative_penalty_invalid) {
3426  return;
3427  } else if (penalty < 0) {
3428  penalty = 0;
3429  }
3430  }
3431 
3432  if (paused_str) {
3433  paused = atoi(paused_str);
3434  if (paused < 0) {
3435  paused = 0;
3436  }
3437  }
3438 
3439  if (wrapuptime_str) {
3440  wrapuptime = atoi(wrapuptime_str);
3441  if (wrapuptime < 0) {
3442  wrapuptime = 0;
3443  }
3444  }
3445 
3446  if ((config_val = ast_variable_retrieve(member_config, category, realtime_ringinuse_field))) {
3447  if (ast_true(config_val)) {
3448  ringinuse = 1;
3449  } else if (ast_false(config_val)) {
3450  ringinuse = 0;
3451  } else {
3452  ast_log(LOG_WARNING, "Invalid value of '%s' field for %s in queue '%s'\n", realtime_ringinuse_field, interface, q->name);
3453  }
3454  }
3455 
3456  /* Find member by realtime uniqueid and update */
3457  mem_iter = ao2_iterator_init(q->members, 0);
3458  while ((m = ao2_iterator_next(&mem_iter))) {
3459  if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) {
3460  m->dead = 0; /* Do not delete this one. */
3461  ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
3462  if (paused_str) {
3463  m->paused = paused;
3464  if (paused && m->lastpause == 0) {
3465  time(&m->lastpause); /* XXX: Should this come from realtime? */
3466  }
3468  AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", q->name, m->interface);
3469  }
3470  if (strcasecmp(state_interface, m->state_interface)) {
3471  ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
3472  }
3473  m->penalty = penalty;
3474  m->ringinuse = ringinuse;
3475  m->wrapuptime = wrapuptime;
3476  found = 1;
3477  ao2_ref(m, -1);
3478  break;
3479  }
3480  ao2_ref(m, -1);
3481  }
3482  ao2_iterator_destroy(&mem_iter);
3483 
3484  /* Create a new member */
3485  if (!found) {
3486  if ((m = create_queue_member(interface, membername, penalty, paused, state_interface, ringinuse, wrapuptime))) {
3487  m->dead = 0;
3488  m->realtime = 1;
3489  ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
3490  if (!log_membername_as_agent) {
3491  ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
3492  } else {
3493  ast_queue_log(q->name, "REALTIME", m->membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
3494  }
3495  member_add_to_queue(q, m);
3496  ao2_ref(m, -1);
3497  m = NULL;
3498  }
3499  }
3500 }
3501 
3502 /*! \brief Iterate through queue's member list and delete them */
3503 static void free_members(struct call_queue *q, int all)
3504 {
3505  /* Free non-dynamic members */
3506  struct member *cur;
3507  struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
3508 
3509  while ((cur = ao2_iterator_next(&mem_iter))) {
3510  if (all || !cur->dynamic) {
3511  member_remove_from_queue(q, cur);
3512  }
3513  ao2_ref(cur, -1);
3514  }
3515  ao2_iterator_destroy(&mem_iter);
3516 }
3517 
3518 /*! \brief Free queue's member list then its string fields */
3519 static void destroy_queue(void *obj)
3520 {
3521  struct call_queue *q = obj;
3522  int i;
3523 
3524  free_members(q, 1);
3526  for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
3527  if (q->sound_periodicannounce[i]) {
3529  }
3530  }
3531  ao2_ref(q->members, -1);
3532 }
3533 
3534 static struct call_queue *alloc_queue(const char *queuename)
3535 {
3536  struct call_queue *q;
3537 
3538  if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) {
3539  if (ast_string_field_init(q, 64)) {
3540  queue_t_unref(q, "String field allocation failed");
3541  return NULL;
3542  }
3543  ast_string_field_set(q, name, queuename);
3544  }
3545  return q;
3546 }
3547 
3548 /*!
3549  * \brief Reload a single queue via realtime.
3550  *
3551  * Check for statically defined queue first, check if deleted RT queue,
3552  * check for new RT queue, if queue vars are not defined init them with defaults.
3553  * reload RT queue vars, set RT queue members dead and reload them, return finished queue.
3554  * \retval the queue,
3555  * \retval NULL if it doesn't exist.
3556  * \note Should be called with the "queues" container locked.
3557 */
3558 static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
3559 {
3560  struct ast_variable *v;
3561  struct call_queue *q, tmpq = {
3562  .name = queuename,
3563  };
3564  struct member *m;
3565  struct ao2_iterator mem_iter;
3566  char *category = NULL;
3567  const char *tmp_name;
3568  char *tmp;
3569  char tmpbuf[64]; /* Must be longer than the longest queue param name. */
3570 
3571  /* Static queues override realtime. */
3572  if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Check if static queue exists"))) {
3573  ao2_lock(q);
3574  if (!q->realtime) {
3575  if (q->dead) {
3576  ao2_unlock(q);
3577  queue_t_unref(q, "Queue is dead; can't return it");
3578  return NULL;
3579  }
3580  ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
3581  ao2_unlock(q);
3582  return q;
3583  }
3584  } else if (!member_config) {
3585  /* Not found in the list, and it's not realtime ... */
3586  return NULL;
3587  }
3588  /* Check if queue is defined in realtime. */
3589  if (!queue_vars) {
3590  /* Delete queue from in-core list if it has been deleted in realtime. */
3591  if (q) {
3592  /*! \note Hmm, can't seem to distinguish a DB failure from a not
3593  found condition... So we might delete an in-core queue
3594  in case of DB failure. */
3595  ast_debug(1, "Queue %s not found in realtime.\n", queuename);
3596 
3597  q->dead = 1;
3598  /* Delete if unused (else will be deleted when last caller leaves). */
3599  queues_t_unlink(queues, q, "Unused; removing from container");
3600  ao2_unlock(q);
3601  queue_t_unref(q, "Queue is dead; can't return it");
3602  }
3603  return NULL;
3604  }
3605 
3606  /* Create a new queue if an in-core entry does not exist yet. */
3607  if (!q) {
3608  struct ast_variable *tmpvar = NULL;
3609  if (!(q = alloc_queue(queuename))) {
3610  return NULL;
3611  }
3612  ao2_lock(q);
3613  clear_queue(q);
3614  q->realtime = 1;
3615  /*Before we initialize the queue, we need to set the strategy, so that linear strategy
3616  * will allocate the members properly
3617  */
3618  for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) {
3619  if (!strcasecmp(tmpvar->name, "strategy")) {
3620  q->strategy = strat2int(tmpvar->value);
3621  if (q->strategy < 0) {
3622  ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
3623  tmpvar->value, q->name);
3625  }
3626  break;
3627  }
3628  }
3629  /* We traversed all variables and didn't find a strategy */
3630  if (!tmpvar) {
3632  }
3633  queues_t_link(queues, q, "Add queue to container");
3634  }
3635  init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
3636 
3637  memset(tmpbuf, 0, sizeof(tmpbuf));
3638  for (v = queue_vars; v; v = v->next) {
3639  /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
3640  if (strchr(v->name, '_')) {
3641  ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
3642  tmp_name = tmpbuf;
3643  tmp = tmpbuf;
3644  while ((tmp = strchr(tmp, '_'))) {
3645  *tmp++ = '-';
3646  }
3647  } else {
3648  tmp_name = v->name;
3649  }
3650 
3651  /* NULL values don't get returned from realtime; blank values should
3652  * still get set. If someone doesn't want a value to be set, they
3653  * should set the realtime column to NULL, not blank. */
3654  queue_set_param(q, tmp_name, v->value, -1, 0);
3655  }
3656 
3657  /* Temporarily set realtime members dead so we can detect deleted ones. */
3658  mem_iter = ao2_iterator_init(q->members, 0);
3659  while ((m = ao2_iterator_next(&mem_iter))) {
3660  if (m->realtime) {
3661  m->dead = 1;
3662  }
3663  ao2_ref(m, -1);
3664  }
3665  ao2_iterator_destroy(&mem_iter);
3666 
3667  while ((category = ast_category_browse(member_config, category))) {
3668  rt_handle_member_record(q, category, member_config);
3669  }
3670 
3671  /* Delete all realtime members that have been deleted in DB. */
3672  mem_iter = ao2_iterator_init(q->members, 0);
3673  while ((m = ao2_iterator_next(&mem_iter))) {
3674  if (m->dead) {
3675  if (ast_strlen_zero(m->membername) || !log_membername_as_agent) {
3676  ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
3677  } else {
3678  ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
3679  }
3681  }
3682  ao2_ref(m, -1);
3683  }
3684  ao2_iterator_destroy(&mem_iter);
3685 
3686  ao2_unlock(q);
3687 
3688  return q;
3689 }
3690 
3691 /*!
3692  * note */
3693 
3694 /*!
3695  * \internal
3696  * \brief Returns reference to the named queue. If the queue is realtime, it will load the queue as well.
3697  * \param queuename - name of the desired queue
3698  *
3699  * \retval the queue
3700  * \retval NULL if it doesn't exist
3701  */
3702 static struct call_queue *find_load_queue_rt_friendly(const char *queuename)
3703 {
3704  struct ast_variable *queue_vars;
3705  struct ast_config *member_config = NULL;
3706  struct call_queue *q = NULL, tmpq = {
3707  .name = queuename,
3708  };
3709  int prev_weight = 0;
3710 
3711  /* Find the queue in the in-core list first. */
3712  q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Look for queue in memory first");
3713 
3714  if (!q || q->realtime) {
3715  /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all
3716  queue operations while waiting for the DB.
3717 
3718  This will be two separate database transactions, so we might
3719  see queue parameters as they were before another process
3720  changed the queue and member list as it was after the change.
3721  Thus we might see an empty member list when a queue is
3722  deleted. In practise, this is unlikely to cause a problem. */
3723 
3724  queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL);
3725  if (queue_vars) {
3726  member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL);
3727  if (!member_config) {
3728  ast_debug(1, "No queue_members defined in config extconfig.conf\n");
3729  member_config = ast_config_new();
3730  }
3731  }
3732  if (q) {
3733  prev_weight = q->weight ? 1 : 0;
3734  queue_t_unref(q, "Need to find realtime queue");
3735  }
3736 
3737  q = find_queue_by_name_rt(queuename, queue_vars, member_config);
3738  ast_config_destroy(member_config);
3739  ast_variables_destroy(queue_vars);
3740 
3741  /* update the use_weight value if the queue's has gained or lost a weight */
3742  if (q) {
3743  if (!q->weight && prev_weight) {
3744  ast_atomic_fetchadd_int(&use_weight, -1);
3745  }
3746  if (q->weight && !prev_weight) {
3747  ast_atomic_fetchadd_int(&use_weight, +1);
3748  }
3749  }
3750  /* Other cases will end up with the proper value for use_weight */
3751  } else {
3753  }
3754  return q;
3755 }
3756 
3757 static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
3758 {
3759  int ret = -1;
3760 
3761  if (ast_strlen_zero(mem->rt_uniqueid)) {
3762  return ret;
3763  }
3764 
3765  if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) > 0) {
3766  ret = 0;
3767  }
3768 
3769  return ret;
3770 }
3771 
3772 
3773 static void update_realtime_members(struct call_queue *q)
3774 {
3775  struct ast_config *member_config = NULL;
3776  struct member *m;
3777  char *category = NULL;
3778  struct ao2_iterator mem_iter;
3779 
3780  if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , SENTINEL))) {
3781  /* This queue doesn't have realtime members. If the queue still has any realtime
3782  * members in memory, they need to be removed.
3783  */
3784  ao2_lock(q);
3785  mem_iter = ao2_iterator_init(q->members, 0);
3786  while ((m = ao2_iterator_next(&mem_iter))) {
3787  if (m->realtime) {
3789  }
3790  ao2_ref(m, -1);
3791  }
3792  ao2_iterator_destroy(&mem_iter);
3793  ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name);
3794  ao2_unlock(q);
3795  return;
3796  }
3797 
3798  ao2_lock(q);
3799 
3800  /* Temporarily set realtime members dead so we can detect deleted ones.*/
3801  mem_iter = ao2_iterator_init(q->members, 0);
3802  while ((m = ao2_iterator_next(&mem_iter))) {
3803  if (m->realtime) {
3804  m->dead = 1;
3805  }
3806  ao2_ref(m, -1);
3807  }
3808  ao2_iterator_destroy(&mem_iter);
3809 
3810  while ((category = ast_category_browse(member_config, category))) {
3811  rt_handle_member_record(q, category, member_config);
3812  }
3813 
3814  /* Delete all realtime members that have been deleted in DB. */
3815  mem_iter = ao2_iterator_init(q->members, 0);
3816  while ((m = ao2_iterator_next(&mem_iter))) {
3817  if (m->dead) {
3818  if (ast_strlen_zero(m->membername) || !log_membername_as_agent) {
3819  ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
3820  } else {
3821  ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
3822  }
3824  }
3825  ao2_ref(m, -1);
3826  }
3827  ao2_iterator_destroy(&mem_iter);
3828  ao2_unlock(q);
3829  ast_config_destroy(member_config);
3830 }
3831 
3832 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
3833 {
3834  struct call_queue *q;
3835  struct queue_ent *cur, *prev = NULL;
3836  int res = -1;
3837  int pos = 0;
3838  int inserted = 0;
3839 
3840  if (!(q = find_load_queue_rt_friendly(queuename))) {
3841  return res;
3842  }
3843  ao2_lock(q);
3844 
3845  /* This is our one */
3846  if (q->joinempty) {
3847  int status = 0;
3848  if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, qe->raise_penalty, q->joinempty, 0))) {
3849  *reason = QUEUE_JOINEMPTY;
3850  ao2_unlock(q);
3851  queue_t_unref(q, "Done with realtime queue");
3852  return res;
3853  }
3854  }
3855  if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen)) {
3856  *reason = QUEUE_FULL;
3857  } else if (*reason == QUEUE_UNKNOWN) {
3858  RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
3859 
3860  /* There's space for us, put us at the right position inside
3861  * the queue.
3862  * Take into account the priority of the calling user */
3863  inserted = 0;
3864  prev = NULL;
3865  cur = q->head;
3866  while (cur) {
3867  /* We have higher priority than the current user, enter
3868  * before him, after all the other users with priority
3869  * higher or equal to our priority. */
3870  if ((!inserted) && (qe->prio > cur->prio)) {
3871  insert_entry(q, prev, qe, &pos);
3872  inserted = 1;
3873  }
3874  /* <= is necessary for the position comparison because it may not be possible to enter
3875  * at our desired position since higher-priority callers may have taken the position we want
3876  */
3877  if (!inserted && (qe->prio >= cur->prio) && position && (position <= pos + 1)) {
3878  insert_entry(q, prev, qe, &pos);
3879  inserted = 1;
3880  /*pos is incremented inside insert_entry, so don't need to add 1 here*/
3881  if (position < pos) {
3882  ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos);
3883  }
3884  }
3885  cur->pos = ++pos;
3886  prev = cur;
3887  cur = cur->next;
3888  }
3889  /* No luck, join at the end of the queue */
3890  if (!inserted) {
3891  insert_entry(q, prev, qe, &pos);
3892  }
3893  ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
3894  ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
3895  ast_copy_string(qe->context, q->context, sizeof(qe->context));
3896  q->count++;
3897  if (q->count == 1) {
3899  }
3900 
3901  res = 0;
3902 
3903  blob = ast_json_pack("{s: s, s: i, s: i}",
3904  "Queue", q->name,
3905  "Position", qe->pos,
3906  "Count", q->count);
3907  ast_channel_publish_cached_blob(qe->chan, queue_caller_join_type(), blob);
3908  ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, ast_channel_name(qe->chan), qe->pos );
3909  }
3910  ao2_unlock(q);
3911  queue_t_unref(q, "Done with realtime queue");
3912 
3913  return res;
3914 }
3915 
3916 static int play_file(struct ast_channel *chan, const char *filename)
3917 {
3918  int res;
3919 
3920  if (ast_strlen_zero(filename)) {
3921  return 0;
3922  }
3923 
3924  if (!ast_fileexists(filename, NULL, ast_channel_language(chan))) {
3925  return 0;
3926  }
3927 
3928  ast_stopstream(chan);
3929 
3930  res = ast_streamfile(chan, filename, ast_channel_language(chan));
3931  if (!res) {
3932  res = ast_waitstream(chan, AST_DIGIT_ANY);
3933  }
3934 
3935  ast_stopstream(chan);
3936 
3937  return res;
3938 }
3939 
3940 /*!
3941  * \brief Check for valid exit from queue via goto
3942  * \retval 0 if failure
3943  * \retval 1 if successful
3944 */
3945 static int valid_exit(struct queue_ent *qe, char digit)
3946 {
3947  int digitlen = strlen(qe->digits);
3948 
3949  /* Prevent possible buffer overflow */
3950  if (digitlen < sizeof(qe->digits) - 2) {
3951  qe->digits[digitlen] = digit;
3952  qe->digits[digitlen + 1] = '\0';
3953  } else {
3954  qe->digits[0] = '\0';
3955  return 0;
3956  }
3957 
3958  /* If there's no context to goto, short-circuit */
3959  if (ast_strlen_zero(qe->context)) {
3960  return 0;
3961  }
3962 
3963  /* If the extension is bad, then reset the digits to blank */
3964  if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1,
3966  qe->digits[0] = '\0';
3967  return 0;
3968  }
3969 
3970  /* We have an exact match */
3971  if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
3972  qe->valid_digits = 1;
3973  /* Return 1 on a successful goto */
3974  return 1;
3975  }
3976 
3977  return 0;
3978 }
3979 
3980 static int say_position(struct queue_ent *qe, int ringing)
3981 {
3982  int res = 0, announceposition = 0;
3983  long avgholdmins, avgholdsecs;
3984  int say_thanks = 1;
3985  time_t now;
3986 
3987  /* Let minannouncefrequency seconds pass between the start of each position announcement */
3988  time(&now);
3989  if ((now - qe->last_pos) < qe->parent->minannouncefrequency) {
3990  return 0;
3991  }
3992 
3993  /* If either our position has changed, or we are over the freq timer, say position */
3994  if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency)) {
3995  return 0;
3996  }
3997 
3998  /* Only announce if the caller's queue position has improved since last time */
3999  if (qe->parent->announceposition_only_up && qe->last_pos_said <= qe->pos) {
4000  return 0;
4001  }
4002 
4003  if (ringing) {
4004  ast_indicate(qe->chan,-1);
4005  } else {
4006  ast_moh_stop(qe->chan);
4007  }
4008 
4012  qe->pos <= qe->parent->announcepositionlimit)) {
4013  announceposition = 1;
4014  }
4015 
4016 
4017  if (announceposition == 1) {
4018  /* Say we're next, if we are */
4019  if (qe->pos == 1) {
4020  res = play_file(qe->chan, qe->parent->sound_next);
4021  if (!res) {
4022  goto posout;
4023  }
4024  /* Say there are more than N callers */
4026  res = (
4027  play_file(qe->chan, qe->parent->queue_quantity1) ||
4029  ast_channel_language(qe->chan), NULL) || /* Needs gender */
4030  play_file(qe->chan, qe->parent->queue_quantity2));
4031  /* Say there are currently N callers waiting */
4032  } else {
4033  res = (
4034  play_file(qe->chan, qe->parent->sound_thereare) ||
4036  ast_channel_language(qe->chan), NULL) || /* Needs gender */
4037  play_file(qe->chan, qe->parent->sound_calls));
4038  }
4039  if (res) {
4040  goto playout;
4041  }
4042  }
4043  /* Round hold time to nearest minute */
4044  avgholdmins = labs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
4045 
4046  /* If they have specified a rounding then round the seconds as well */
4047  if (qe->parent->roundingseconds) {
4048  avgholdsecs = (labs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
4049  avgholdsecs *= qe->parent->roundingseconds;
4050  } else {
4051  avgholdsecs = 0;
4052  }
4053 
4054  ast_verb(3, "Hold time for %s is %ld minute(s) %ld seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
4055 
4056  /* If the hold time is >1 min, if it's enabled, and if it's not
4057  supposed to be only once and we have already said it, say it */
4058  if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime &&
4061  res = play_file(qe->chan, qe->parent->sound_holdtime);
4062  if (res) {
4063  goto playout;
4064  }
4065 
4066  if (avgholdmins >= 1) {
4067  res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, ast_channel_language(qe->chan), NULL);
4068  if (res) {
4069  goto playout;
4070  }
4071 
4072  if (avgholdmins == 1) {
4073  res = play_file(qe->chan, qe->parent->sound_minute);
4074  if (res) {
4075  goto playout;
4076  }
4077  } else {
4078  res = play_file(qe->chan, qe->parent->sound_minutes);
4079  if (res) {
4080  goto playout;
4081  }
4082  }
4083  }
4084  if (avgholdsecs >= 1) {
4085  res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, ast_channel_language(qe->chan), NULL);
4086  if (res) {
4087  goto playout;
4088  }
4089 
4090  res = play_file(qe->chan, qe->parent->sound_seconds);
4091  if (res) {
4092  goto playout;
4093  }
4094  }
4095  } else if (qe->parent->announceholdtime && !qe->parent->announceposition) {
4096  say_thanks = 0;
4097  }
4098 
4099 posout:
4100  if (qe->parent->announceposition) {
4101  ast_verb(3, "Told %s in %s their queue position (which was %d)\n",
4102  ast_channel_name(qe->chan), qe->parent->name, qe->pos);
4103  }
4104  if (say_thanks) {
4105  res = play_file(qe->chan, qe->parent->sound_thanks);
4106  }
4107 playout:
4108 
4109  if ((res > 0 && !valid_exit(qe, res))) {
4110  res = 0;
4111  }
4112 
4113  /* Set our last_pos indicators */
4114  qe->last_pos = now;
4115  qe->last_pos_said = qe->pos;
4116 
4117  /* Don't restart music on hold if we're about to exit the caller from the queue */
4118  if (!res) {
4119  if (ringing) {
4121  } else {
4122  ast_moh_start(qe->chan, qe->moh, NULL);
4123  }
4124  }
4125  return res;
4126 }
4127 
4128 static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
4129 {
4130  int oldvalue;
4131 
4132  /* Calculate holdtime using an exponential average */
4133  /* Thanks to SRT for this contribution */
4134  /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
4135 
4136  ao2_lock(qe->parent);
4137  if ((qe->parent->callscompleted + qe->parent->callsabandoned) == 0) {
4138  qe->parent->holdtime = newholdtime;
4139  } else {
4140  oldvalue = qe->parent->holdtime;
4141  qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
4142  }
4143  ao2_unlock(qe->parent);
4144 }
4145 
4146 /*! \brief Caller leaving queue.
4147  *
4148  * Search the queue to find the leaving client, if found remove from queue
4149  * create manager event, move others up the queue.
4150 */
4151 static void leave_queue(struct queue_ent *qe)
4152 {
4153  struct call_queue *q;
4154  struct queue_ent *current, *prev = NULL;
4155  struct penalty_rule *pr_iter;
4156  int pos = 0;
4157 
4158  if (!(q = qe->parent)) {
4159  return;
4160  }
4161  queue_t_ref(q, "Copy queue pointer from queue entry");
4162  ao2_lock(q);
4163 
4164  prev = NULL;
4165  for (current = q->head; current; current = current->next) {
4166  if (current == qe) {
4167  RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4168  char posstr[20];
4169  q->count--;
4170  if (!q->count) {
4172  }
4173 
4174  blob = ast_json_pack("{s: s, s: i, s: i}",
4175  "Queue", q->name,
4176  "Position", qe->pos,
4177  "Count", q->count);
4178  ast_channel_publish_cached_blob(qe->chan, queue_caller_leave_type(), blob);
4179  ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, ast_channel_name(qe->chan));
4180  /* Take us out of the queue */
4181  if (prev) {
4182  prev->next = current->next;
4183  } else {
4184  q->head = current->next;
4185  }
4186  /* Free penalty rules */
4187  while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list))) {
4188  ast_free(pr_iter);
4189  }
4190  qe->pr = NULL;
4191  snprintf(posstr, sizeof(posstr), "%d", qe->pos);
4192  pbx_builtin_setvar_helper(qe->chan, "QUEUEPOSITION", posstr);
4193  } else {
4194  /* Renumber the people after us in the queue based on a new count */
4195  current->pos = ++pos;
4196  prev = current;
4197  }
4198  }
4199  ao2_unlock(q);
4200 
4201  /*If the queue is a realtime queue, check to see if it's still defined in real time*/
4202  if (q->realtime) {
4203  struct ast_variable *var;
4204  if (!(var = ast_load_realtime("queues", "name", q->name, SENTINEL))) {
4205  q->dead = 1;
4206  } else {
4207  ast_variables_destroy(var);
4208  }
4209  }
4210 
4211  if (q->dead) {
4212  /* It's dead and nobody is in it, so kill it */
4213  queues_t_unlink(queues, q, "Queue is now dead; remove it from the container");
4214  }
4215  /* unref the explicit ref earlier in the function */
4216  queue_t_unref(q, "Expire copied reference");
4217 }
4218 
4219 /*!
4220  * \internal
4221  * \brief Destroy the given callattempt structure and free it.
4222  * \since 1.8
4223  *
4224  * \param doomed callattempt structure to destroy.
4225  *
4226  * \return Nothing
4227  */
4228 static void callattempt_free(struct callattempt *doomed)
4229 {
4230  if (doomed->member) {
4231  ao2_ref(doomed->member, -1);
4232  }
4234  ast_free(doomed->orig_chan_name);
4235  ast_free(doomed);
4236 }
4237 
4238 static void publish_dial_end_event(struct ast_channel *in, struct callattempt *outgoing, struct ast_channel *exception, const char *status)
4239 {
4240  struct callattempt *cur;
4241 
4242  for (cur = outgoing; cur; cur = cur->q_next) {
4243  if (cur->chan && cur->chan != exception) {
4244  ast_channel_publish_dial(in, cur->chan, NULL, status);
4245  }
4246  }
4247 }
4248 
4249 /*! \brief Hang up a list of outgoing calls */
4250 static void hangupcalls(struct queue_ent *qe, struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere)
4251 {
4252  struct callattempt *oo;
4253 
4254  while (outgoing) {
4255  /* If someone else answered the call we should indicate this in the CANCEL */
4256  /* Hangup any existing lines we have open */
4257  if (outgoing->chan && (outgoing->chan != exception)) {
4258  if (exception || cancel_answered_elsewhere) {
4260  }
4261  ast_channel_publish_dial(qe->chan, outgoing->chan, outgoing->interface, "CANCEL");
4262 
4263  /* When dialing channels it is possible that they may not ever
4264  * leave the not in use state (Local channels in particular) by
4265  * the time we cancel them. If this occurs but we know they were
4266  * dialed we explicitly remove them from the pending members
4267  * container so that subsequent call attempts occur.
4268  */
4269  if (outgoing->member->status == AST_DEVICE_NOT_INUSE) {
4270  pending_members_remove(outgoing->member);
4271  }
4272 
4273  ast_hangup(outgoing->chan);
4274  }
4275  oo = outgoing;
4276  outgoing = outgoing->q_next;
4278  callattempt_free(oo);
4279  }
4280 }
4281 
4282 /*!
4283  * \brief Get the number of members available to accept a call.
4284  *
4285  * \note The queue passed in should be locked prior to this function call
4286  *
4287  * \param[in] q The queue for which we are couting the number of available members
4288  * \return Return the number of available members in queue q
4289  */
4290 static int num_available_members(struct call_queue *q)
4291 {
4292  struct member *mem;
4293  int avl = 0;
4294  struct ao2_iterator mem_iter;
4295 
4296  mem_iter = ao2_iterator_init(q->members, 0);
4297  while ((mem = ao2_iterator_next(&mem_iter))) {
4298 
4299  avl += is_member_available(q, mem);
4300  ao2_ref(mem, -1);
4301 
4302  /* If autofill is not enabled or if the queue's strategy is ringall, then
4303  * we really don't care about the number of available members so much as we
4304  * do that there is at least one available.
4305  *
4306  * In fact, we purposely will return from this function stating that only
4307  * one member is available if either of those conditions hold. That way,
4308  * functions which determine what action to take based on the number of available
4309  * members will operate properly. The reasoning is that even if multiple
4310  * members are available, only the head caller can actually be serviced.
4311  */
4312  if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) {
4313  break;
4314  }
4315  }
4316  ao2_iterator_destroy(&mem_iter);
4317 
4318  return avl;
4319 }
4320 
4321 /* traverse all defined queues which have calls waiting and contain this member
4322  return 0 if no other queue has precedence (higher weight) or 1 if found */
4323 static int compare_weight(struct call_queue *rq, struct member *member)
4324 {
4325  struct call_queue *q;
4326  struct member *mem;
4327  int found = 0;
4328  struct ao2_iterator queue_iter;
4329 
4330  queue_iter = ao2_iterator_init(queues, 0);
4331  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
4332  if (q == rq) { /* don't check myself, could deadlock */
4333  queue_t_unref(q, "Done with iterator");
4334  continue;
4335  }
4336  ao2_lock(q);
4337  if (q->count && q->members) {
4338  if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
4339  ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
4340  if (q->weight > rq->weight && q->count >= num_available_members(q)) {
4341  ast_debug(1, "Queue '%s' (weight %d, calls %d) is preferred over '%s' (weight %d, calls %d)\n", q->name, q->weight, q->count, rq->name, rq->weight, rq->count);
4342  found = 1;
4343  }
4344  ao2_ref(mem, -1);
4345  }
4346  }
4347  ao2_unlock(q);
4348  queue_t_unref(q, "Done with iterator");
4349  if (found) {
4350  break;
4351  }
4352  }
4353  ao2_iterator_destroy(&queue_iter);
4354  return found;
4355 }
4356 
4357 /*! \brief common hangup actions */
4358 static void do_hang(struct callattempt *o)
4359 {
4360  o->stillgoing = 0;
4361  ast_hangup(o->chan);
4363  o->chan = NULL;
4364 }
4365 
4366 /*!
4367  * \internal
4368  * \brief Check if the member status is available.
4369  *
4370  * \param status Member status to check if available.
4371  *
4372  * \retval non-zero if the member status is available.
4373  */
4375 {
4376  return status == AST_DEVICE_NOT_INUSE || status == AST_DEVICE_UNKNOWN;
4377 }
4378 
4379 /*!
4380  * \internal
4381  * \brief Determine if can ring a queue entry.
4382  *
4383  * \param qe Queue entry to check.
4384  * \param call Member call attempt.
4385  *
4386  * \retval non-zero if an entry can be called.
4387  */
4388 static int can_ring_entry(struct queue_ent *qe, struct callattempt *call)
4389 {
4390  struct member *memberp = call->member;
4391  int wrapuptime;
4392 
4393  if (memberp->paused) {
4394  ast_debug(1, "%s paused, can't receive call\n", call->interface);
4395  return 0;
4396  }
4397 
4398  if (!memberp->ringinuse && !member_status_available(memberp->status)) {
4399  ast_debug(1, "%s not available, can't receive call\n", call->interface);
4400  return 0;
4401  }
4402 
4403  if (memberp->lastqueue) {
4404  wrapuptime = get_wrapuptime(memberp->lastqueue, memberp);
4405  } else {
4406  wrapuptime = get_wrapuptime(qe->parent, memberp);
4407  }
4408  if (wrapuptime && (time(NULL) - memberp->lastcall) < wrapuptime) {
4409  ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
4410  (memberp->lastqueue ? memberp->lastqueue->name : qe->parent->name),
4411  call->interface);
4412  return 0;
4413  }
4414 
4415  if (use_weight && compare_weight(qe->parent, memberp)) {
4416  ast_debug(1, "Priority queue delaying call to %s:%s\n",
4417  qe->parent->name, call->interface);
4418  return 0;
4419  }
4420 
4421  if (!memberp->ringinuse) {
4422  struct member *mem;
4423 
4424  ao2_lock(pending_members);
4425 
4426  mem = ao2_find(pending_members, memberp,
4428  if (mem) {
4429  /*
4430  * If found that means this member is currently being attempted
4431  * from another calling thread, so stop trying from this thread
4432  */
4433  ast_debug(1, "%s has another call trying, can't receive call\n",
4434  call->interface);
4435  ao2_ref(mem, -1);
4436  ao2_unlock(pending_members);
4437  return 0;
4438  }
4439 
4440  /*
4441  * If not found add it to the container so another queue
4442  * won't attempt to call this member at the same time.
4443  */
4444  ast_debug(3, "Add %s to pending_members\n", memberp->membername);
4445  ao2_link(pending_members, memberp);
4446  ao2_unlock(pending_members);
4447 
4448  /*
4449  * The queue member is available. Get current status to be sure
4450  * because the device state and extension state callbacks may
4451  * not have updated the status yet.
4452  */
4454  ast_debug(1, "%s actually not available, can't receive call\n",
4455  call->interface);
4456  pending_members_remove(memberp);
4457  return 0;
4458  }
4459  }
4460 
4461  return 1;
4462 }
4463 
4464 /*!
4465  * \brief Part 2 of ring_one
4466  *
4467  * Does error checking before attempting to request a channel and call a member.
4468  * This function is only called from ring_one().
4469  * Failure can occur if:
4470  * - Agent on call
4471  * - Agent is paused
4472  * - Wrapup time not expired
4473  * - Priority by another queue
4474  *
4475  * \retval 1 on success to reach a free agent
4476  * \retval 0 on failure to get agent.
4477  */
4478 static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
4479 {
4480  int res;
4481  int status;
4482  char tech[256];
4483  char *location;
4484  const char *macrocontext, *macroexten;
4485  struct ast_format_cap *nativeformats;
4486  RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4487 
4488  /* on entry here, we know that tmp->chan == NULL */
4489  if (!can_ring_entry(qe, tmp)) {
4490  tmp->stillgoing = 0;
4491  ++*busies;
4492  return 0;
4493  }
4494 
4495  ast_copy_string(tech, tmp->interface, sizeof(tech));
4496  if ((location = strchr(tech, '/'))) {
4497  *location++ = '\0';
4498  } else {
4499  location = "";
4500  }
4501 
4502  ast_channel_lock(qe->chan);
4503  nativeformats = ao2_bump(ast_channel_nativeformats(qe->chan));
4504  ast_channel_unlock(qe->chan);
4505 
4506  /* Request the peer */
4507  tmp->chan = ast_request(tech, nativeformats, NULL, qe->chan, location, &status);
4508  ao2_cleanup(nativeformats);
4509  if (!tmp->chan) { /* If we can't, just go on to the next call */
4510  ao2_lock(qe->parent);
4511  qe->parent->rrpos++;
4512  qe->linpos++;
4513  ao2_unlock(qe->parent);
4514 
4516 
4517  publish_dial_end_event(qe->chan, tmp, NULL, "BUSY");
4518  tmp->stillgoing = 0;
4519  ++*busies;
4520  return 0;
4521  }
4522 
4523  ast_channel_lock_both(tmp->chan, qe->chan);
4524 
4527  if (qe->cancel_answered_elsewhere) {
4529  }
4530  ast_channel_appl_set(tmp->chan, "AppQueue");
4531  ast_channel_data_set(tmp->chan, "(Outgoing Line)");
4532  memset(ast_channel_whentohangup(tmp->chan), 0, sizeof(*ast_channel_whentohangup(tmp->chan)));
4533 
4534  /* If the new channel has no callerid, try to guess what it should be */
4535  if (!ast_channel_caller(tmp->chan)->id.number.valid) {
4537  struct ast_party_caller caller;
4538 
4540  caller.id = ast_channel_connected(qe->chan)->id;
4541  caller.ani = ast_channel_connected(qe->chan)->ani;
4542  ast_channel_set_caller_event(tmp->chan, &caller, NULL);
4543  } else if (!ast_strlen_zero(ast_channel_dialed(qe->chan)->number.str)) {
4547  }
4548  tmp->dial_callerid_absent = 1;
4549  }
4550 
4552 
4554 
4556 
4557  /* Inherit specially named variables from parent channel */
4561 
4562  /* Presense of ADSI CPE on outgoing channel follows ours */
4564 
4565  /* Inherit context and extension */
4566  macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT");
4567  ast_channel_dialcontext_set(tmp->chan, ast_strlen_zero(macrocontext) ? ast_channel_context(qe->chan) : macrocontext);
4568  macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN");
4569  if (!ast_strlen_zero(macroexten)) {
4570  ast_channel_exten_set(tmp->chan, macroexten);
4571  } else {
4573  }
4574 
4575  /* Save the original channel name to detect call pickup masquerading in. */
4577 
4578  ast_channel_unlock(tmp->chan);
4579  ast_channel_unlock(qe->chan);
4580 
4581  /* PREDIAL: Run gosub on the callee's channel */
4582  if (qe->predial_callee) {
4583  ast_pre_call(tmp->chan, qe->predial_callee);
4584  }
4585 
4586  /* Place the call, but don't wait on the answer */
4587  if ((res = ast_call(tmp->chan, location, 0))) {
4588  /* Again, keep going even if there's an error */
4589  ast_verb(3, "Couldn't call %s\n", tmp->interface);
4590  do_hang(tmp);
4591  ++*busies;
4592  return 0;
4593  }
4594 
4595  ast_channel_lock_both(tmp->chan, qe->chan);
4596 
4597  blob = ast_json_pack("{s: s, s: s, s: s}",
4598  "Queue", qe->parent->name,
4599  "Interface", tmp->interface,
4600  "MemberName", tmp->member->membername);
4601  queue_publish_multi_channel_blob(qe->chan, tmp->chan, queue_agent_called_type(), blob);
4602 
4603  ast_channel_publish_dial(qe->chan, tmp->chan, tmp->interface, NULL);
4604 
4605  ast_channel_unlock(tmp->chan);
4606  ast_channel_unlock(qe->chan);
4607 
4608  ast_verb(3, "Called %s\n", tmp->interface);
4609 
4610  return 1;
4611 }
4612 
4613 /*! \brief find the entry with the best metric, or NULL */
4615 {
4616  struct callattempt *best = NULL, *cur;
4617 
4618  for (cur = outgoing; cur; cur = cur->q_next) {
4619  if (cur->stillgoing && /* Not already done */
4620  !cur->chan && /* Isn't already going */
4621  (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */
4622  best = cur;
4623  }
4624  }
4625 
4626  return best;
4627 }
4628 
4629 /*!
4630  * \brief Place a call to a queue member.
4631  *
4632  * Once metrics have been calculated for each member, this function is used
4633  * to place a call to the appropriate member (or members). The low-level
4634  * channel-handling and error detection is handled in ring_entry
4635  *
4636  * \retval 1 if a member was called successfully
4637  * \retval 0 otherwise
4638  */
4639 static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
4640 {
4641  int ret = 0;
4642  struct callattempt *cur;
4643 
4644  if (qe->predial_callee) {
4646  for (cur = outgoing; cur; cur = cur->q_next) {
4647  if (cur->stillgoing && cur->chan) {
4649  }
4650  }
4651  }
4652 
4653  while (ret == 0) {
4654  struct callattempt *best = find_best(outgoing);
4655  if (!best) {
4656  ast_debug(1, "Nobody left to try ringing in queue\n");
4657  break;
4658  }
4659  if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
4660  /* Ring everyone who shares this best metric (for ringall) */
4661  for (cur = outgoing; cur; cur = cur->q_next) {
4662  if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
4663  ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
4664  ret |= ring_entry(qe, cur, busies);
4665  if (qe->predial_callee && cur->chan) {
4667  }
4668  }
4669  }
4670  } else {
4671  /* Ring just the best channel */
4672  ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric);
4673  ret = ring_entry(qe, best, busies);
4674  if (qe->predial_callee && best->chan) {
4675  ast_autoservice_start(best->chan);
4676  }
4677  }
4678 
4679  /* If we have timed out, break out */
4680  if (qe->expire && (time(NULL) >= qe->expire)) {
4681  ast_debug(1, "Queue timed out while ringing members.\n");
4682  ret = 0;
4683  break;
4684  }
4685  }
4686  if (qe->predial_callee) {
4687  for (cur = outgoing; cur; cur = cur->q_next) {
4688  if (cur->stillgoing && cur->chan) {
4689  ast_autoservice_stop(cur->chan);
4690  }
4691  }
4693  }
4694 
4695  return ret;
4696 }
4697 
4698 /*! \brief Search for best metric and add to Round Robbin queue */
4699 static int store_next_rr(struct queue_ent *qe, struct callattempt *outgoing)
4700 {
4701  struct callattempt *best = find_best(outgoing);
4702 
4703  if (best) {
4704  /* Ring just the best channel */
4705  ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
4706  qe->parent->rrpos = best->metric % 1000;
4707  } else {
4708  /* Just increment rrpos */
4709  if (qe->parent->wrapped) {
4710  /* No more channels, start over */
4711  qe->parent->rrpos = 0;
4712  } else {
4713  /* Prioritize next entry */
4714  qe->parent->rrpos++;
4715  }
4716  }
4717  qe->parent->wrapped = 0;
4718 
4719  return 0;
4720 }
4721 
4722 /*! \brief Search for best metric and add to Linear queue */
4723 static int store_next_lin(struct queue_ent *qe, struct callattempt *outgoing)
4724 {
4725  struct callattempt *best = find_best(outgoing);
4726 
4727  if (best) {
4728  /* Ring just the best channel */
4729  ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
4730  qe->linpos = best->metric % 1000;
4731  } else {
4732  /* Just increment rrpos */
4733  if (qe->linwrapped) {
4734  /* No more channels, start over */
4735  qe->linpos = 0;
4736  } else {
4737  /* Prioritize next entry */
4738  qe->linpos++;
4739  }
4740  }
4741  qe->linwrapped = 0;
4742 
4743  return 0;
4744 }
4745 
4746 /*! \brief Playback announcement to queued members if period has elapsed */
4747 static int say_periodic_announcement(struct queue_ent *qe, int ringing)
4748 {
4749  int res = 0;
4750  time_t now;
4751 
4752  /* Get the current time */
4753  time(&now);
4754 
4755  /* Check to see if it is time to announce */
4757  return 0;
4758  }
4759 
4760  /* Stop the music on hold so we can play our own file */
4761  if (ringing) {
4762  ast_indicate(qe->chan,-1);
4763  } else {
4764  ast_moh_stop(qe->chan);
4765  }
4766 
4767  ast_verb(3, "Playing periodic announcement\n");
4768 
4770  qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce;
4771  } else if (qe->last_periodic_announce_sound >= qe->parent->numperiodicannounce ||
4774  }
4775 
4776  /* play the announcement */
4778 
4779  if (res > 0 && !valid_exit(qe, res)) {
4780  res = 0;
4781  }
4782 
4783  /* Resume Music on Hold if the caller is going to stay in the queue */
4784  if (!res) {
4785  if (ringing) {
4787  } else {
4788  ast_moh_start(qe->chan, qe->moh, NULL);
4789  }
4790  }
4791 
4792  /* update last_periodic_announce_time */
4793  if (qe->parent->relativeperiodicannounce) {
4794  time(&qe->last_periodic_announce_time);
4795  } else {
4796  qe->last_periodic_announce_time = now;
4797  }
4798 
4799  /* Update the current periodic announcement to the next announcement */
4800  if (!qe->parent->randomperiodicannounce) {
4802  }
4803 
4804  return res;
4805 }
4806 
4807 /*! \brief Record that a caller gave up on waiting in queue */
4808 static void record_abandoned(struct queue_ent *qe)
4809 {
4810  int callabandonedinsl = 0;
4811  time_t now;
4812 
4813  RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4814 
4815  pbx_builtin_setvar_helper(qe->chan, "ABANDONED", "TRUE");
4816 
4817  set_queue_variables(qe->parent, qe->chan);
4818  ao2_lock(qe->parent);
4819  blob = ast_json_pack("{s: s, s: i, s: i, s: i}",
4820  "Queue", qe->parent->name,
4821  "Position", qe->pos,
4822  "OriginalPosition", qe->opos,
4823  "HoldTime", (int)(time(NULL) - qe->start));
4824 
4825 
4826  time(&now);
4827  callabandonedinsl = ((now - qe->start) <= qe->parent->servicelevel);
4828  if (callabandonedinsl) {
4829  qe->parent->callsabandonedinsl++;
4830  }
4831 
4832  qe->parent->callsabandoned++;
4833  ao2_unlock(qe->parent);
4834 
4835  ast_channel_publish_cached_blob(qe->chan, queue_caller_abandon_type(), blob);
4836 }
4837 
4838 /*! \brief RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. */
4839 static void rna(int rnatime, struct queue_ent *qe, struct ast_channel *peer, char *interface, char *membername, int autopause)
4840 {
4841  RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4842 
4843  ast_verb(3, "Nobody picked up in %d ms\n", rnatime);
4844 
4845  /* Stop ringing, and resume MOH if specified */
4846  if (qe->ring_when_ringing) {
4847  ast_indicate(qe->chan, -1);
4848  ast_moh_start(qe->chan, qe->moh, NULL);
4849  }
4850 
4851  blob = ast_json_pack("{s: s, s: s, s: s, s: i}",
4852  "Queue", qe->parent->name,
4853  "Interface", interface,
4854  "MemberName", membername,
4855  "RingTime", rnatime);
4856  queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_ringnoanswer_type(), blob);
4857 
4858  ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), membername, "RINGNOANSWER", "%d", rnatime);
4859  if (qe->parent->autopause != QUEUE_AUTOPAUSE_OFF && autopause) {
4860  if (qe->parent->autopausedelay > 0) {
4861  struct member *mem;
4862  ao2_lock(qe->parent);
4863  if ((mem = interface_exists(qe->parent, interface))) {
4864  time_t idletime = time(&idletime)-mem->lastcall;
4865  if ((mem->lastcall != 0) && (qe->parent->autopausedelay > idletime)) {
4866  ao2_unlock(qe->parent);
4867  ao2_ref(mem, -1);
4868  return;
4869  }
4870  ao2_ref(mem, -1);
4871  }
4872  ao2_unlock(qe->parent);
4873  }
4874  if (qe->parent->autopause == QUEUE_AUTOPAUSE_ON) {
4875  if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) {
4876  ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n",
4877  interface, qe->parent->name);
4878  } else {
4879  ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
4880  }
4881  } else {
4882  /* If queue autopause is mode all, just don't send any queue to stop.
4883  * the function will stop in all queues */
4884  if (!set_member_paused("", interface, "Auto-Pause", 1)) {
4885  ast_verb(3, "Auto-Pausing Queue Member %s in all queues since they failed to answer on queue %s.\n",
4886  interface, qe->parent->name);
4887  } else {
4888  ast_verb(3, "Failed to pause Queue Member %s in all queues!\n", interface);
4889  }
4890  }
4891  }
4892  return;
4893 }
4894 
4895 /*!
4896  * \internal
4897  * \brief Update connected line on chan from peer.
4898  * \since 13.6.0
4899  *
4900  * \param chan Channel to get connected line updated.
4901  * \param peer Channel providing connected line information.
4902  * \param is_caller Non-zero if chan is the calling channel.
4903  *
4904  * \return Nothing
4905  */
4906 static void update_connected_line_from_peer(struct ast_channel *chan, struct ast_channel *peer, int is_caller)
4907 {
4908  struct ast_party_connected_line connected_caller;
4909 
4910  ast_party_connected_line_init(&connected_caller);
4911 
4912  ast_channel_lock(peer);
4913  ast_connected_line_copy_from_caller(&connected_caller, ast_channel_caller(peer));
4914  ast_channel_unlock(peer);
4916  if (ast_channel_connected_line_sub(peer, chan, &connected_caller, 0)
4917  && ast_channel_connected_line_macro(peer, chan, &connected_caller, is_caller, 0)) {
4918  ast_channel_update_connected_line(chan, &connected_caller, NULL);
4919  }
4920  ast_party_connected_line_free(&connected_caller);
4921 }
4922 
4923 #define AST_MAX_WATCHERS 256
4924 /*!
4925  * \brief Wait for a member to answer the call
4926  *
4927  * \param[in] qe the queue_ent corresponding to the caller in the queue
4928  * \param[in] outgoing the list of callattempts. Relevant ones will have their chan and stillgoing parameters non-zero
4929  * \param[in] to the amount of time (in milliseconds) to wait for a response
4930  * \param[out] digit if a user presses a digit to exit the queue, this is the digit the caller pressed
4931  * \param[in] prebusies number of busy members calculated prior to calling wait_for_answer
4932  * \param[in] caller_disconnect if the 'H' option is used when calling Queue(), this is used to detect if the caller pressed * to disconnect the call
4933  * \param[in] forwardsallowed used to detect if we should allow call forwarding, based on the 'i' option to Queue()
4934  *
4935  * \todo eventually all call forward logic should be intergerated into and replaced by ast_call_forward()
4936  */
4937 static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
4938 {
4939  const char *queue = qe->parent->name;
4940  struct callattempt *o, *start = NULL, *prev = NULL;
4941  int status;
4942  int numbusies = prebusies;
4943  int numnochan = 0;
4944  int stillgoing = 0;
4945  int orig = *to;
4946  struct ast_frame *f;
4947  struct callattempt *peer = NULL;
4948  struct ast_channel *winner;
4949  struct ast_channel *in = qe->chan;
4950  char on[80] = "";
4951  char membername[80] = "";
4952  long starttime = 0;
4953  long endtime = 0;
4954  char *inchan_name;
4955  struct timeval start_time_tv = ast_tvnow();
4956  int canceled_by_caller = 0; /* 1 when caller hangs up or press digit or press * */
4957 
4958  ast_channel_lock(qe->chan);
4959  inchan_name = ast_strdupa(ast_channel_name(qe->chan));
4960  ast_channel_unlock(qe->chan);
4961 
4962  starttime = (long) time(NULL);
4963 
4964  while ((*to = ast_remaining_ms(start_time_tv, orig)) && !peer) {
4965  int numlines, retry, pos = 1;
4966  struct ast_channel *watchers[AST_MAX_WATCHERS];
4967  watchers[0] = in;
4968  start = NULL;
4969 
4970  for (retry = 0; retry < 2; retry++) {
4971  numlines = 0;
4972  for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
4973  if (o->stillgoing) { /* Keep track of important channels */
4974  stillgoing = 1;
4975  if (o->chan) {
4976  if (pos < AST_MAX_WATCHERS) {
4977  watchers[pos++] = o->chan;
4978  }
4979  if (!start) {
4980  start = o;
4981  } else {
4982  prev->call_next = o;
4983  }
4984  prev = o;
4985  }
4986  } else if (prev) {
4987  prev->call_next = NULL;
4988  }
4989  numlines++;
4990  }
4991  if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
4992  (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */) {
4993  break;
4994  }
4995  /* On "ringall" strategy we only move to the next penalty level
4996  when *all* ringing phones are done in the current penalty level */
4997  ring_one(qe, outgoing, &numbusies);
4998  /* and retry... */
4999  }
5000  if (pos == 1 /* not found */) {
5001  if (numlines == (numbusies + numnochan)) {
5002  ast_debug(1, "Everyone is busy at this time\n");
5003  } else {
5004  ast_debug(3, "No one is answering queue '%s' (%d numlines / %d busies / %d failed channels)\n", queue, numlines, numbusies, numnochan);
5005  }
5006  *to = 0;
5007  return NULL;
5008  }
5009 
5010  /* Poll for events from both the incoming channel as well as any outgoing channels */
5011  winner = ast_waitfor_n(watchers, pos, to);
5012 
5013  /* Service all of the outgoing channels */
5014  for (o = start; o; o = o->call_next) {
5015  /* We go with a fixed buffer here instead of using ast_strdupa. Using
5016  * ast_strdupa in a loop like this one can cause a stack overflow
5017  */
5018  char ochan_name[AST_CHANNEL_NAME];
5019 
5020  if (o->chan) {
5021  ast_channel_lock(o->chan);
5022  ast_copy_string(ochan_name, ast_channel_name(o->chan), sizeof(ochan_name));
5024  }
5025  if (o->stillgoing && (o->chan) && (ast_channel_state(o->chan) == AST_STATE_UP)) {
5026  if (!peer) {
5027  ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
5028  if (o->orig_chan_name
5029  && strcmp(o->orig_chan_name, ochan_name)) {
5030  /*
5031  * The channel name changed so we must generate COLP update.
5032  * Likely because a call pickup channel masqueraded in.
5033  */
5035  } else if (!o->block_connected_update) {
5036  if (o->pending_connected_update) {
5037  if (ast_channel_connected_line_sub(o->chan, in, &o->connected, 0) &&
5038  ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
5040  }
5041  } else if (!o->dial_callerid_absent) {
5043  }
5044  }
5045  if (o->aoc_s_rate_list) {
5046  size_t encoded_size;
5047  struct ast_aoc_encoded *encoded;
5048  if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
5049  ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
5050  ast_aoc_destroy_encoded(encoded);
5051  }
5052  }
5053  peer = o;
5054  }
5055  } else if (o->chan && (o->chan == winner)) {
5056 
5057  ast_copy_string(on, o->member->interface, sizeof(on));
5058  ast_copy_string(membername, o->member->membername, sizeof(membername));
5059 
5060  /* Before processing channel, go ahead and check for forwarding */
5061  if (!ast_strlen_zero(ast_channel_call_forward(o->chan)) && !forwardsallowed) {
5062  ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, ast_channel_call_forward(o->chan));
5064  "CANCEL", ast_channel_call_forward(o->chan));
5065  numnochan++;
5066  do_hang(o);
5067  winner = NULL;
5068  continue;
5069  } else if (!ast_strlen_zero(ast_channel_call_forward(o->chan))) {
5070  struct ast_channel *original = o->chan;
5071  char forwarder[AST_CHANNEL_NAME];
5072  char tmpchan[256];
5073  char *stuff;
5074  char *tech;
5075  int failed = 0;
5076 
5077  ast_copy_string(tmpchan, ast_channel_call_forward(o->chan), sizeof(tmpchan));
5078  ast_copy_string(forwarder, ast_channel_name(o->chan), sizeof(forwarder));
5079  if ((stuff = strchr(tmpchan, '/'))) {
5080  *stuff++ = '\0';
5081  tech = tmpchan;
5082  } else {
5083  const char *forward_context;
5084  ast_channel_lock(o->chan);
5085  forward_context = pbx_builtin_getvar_helper(o->chan, "FORWARD_CONTEXT");
5086  snprintf(tmpchan, sizeof(tmpchan), "%s@%s", ast_channel_call_forward(o->chan), forward_context ? forward_context : ast_channel_context(o->chan));
5088  stuff = tmpchan;
5089  tech = "Local";
5090  }
5091  if (!strcasecmp(tech, "Local")) {
5092  /*
5093  * Drop the connected line update block for local channels since
5094  * this is going to run dialplan and the user can change his
5095  * mind about what connected line information he wants to send.
5096  */
5097  o->block_connected_update = 0;
5098  }
5099 
5100  ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name);
5101  /* Setup parameters */
5102  o->chan = ast_request(tech, ast_channel_nativeformats(in), NULL, in, stuff, &status);
5103  if (!o->chan) {
5105  "Forwarding failed to create channel to dial '%s/%s'\n",
5106  tech, stuff);
5107  o->stillgoing = 0;
5108  numnochan++;
5109  } else {
5110  ast_channel_lock_both(o->chan, original);
5112  ast_channel_redirecting(original));
5114  ast_channel_unlock(original);
5115 
5116  ast_channel_lock_both(o->chan, in);
5119  pbx_builtin_setvar_helper(o->chan, "FORWARDERNAME", forwarder);
5121 
5122  if (o->pending_connected_update) {
5123  /*
5124  * Re-seed the callattempt's connected line information with
5125  * previously acquired connected line info from the queued
5126  * channel. The previously acquired connected line info could
5127  * have been set through the CONNECTED_LINE dialplan function.
5128  */
5129  o->pending_connected_update = 0;
5131  }
5132 
5135 
5137 
5140  /*
5141  * The call was not previously redirected so it is
5142  * now redirected from this number.
5143  */
5149  }
5150 
5152 
5156  ast_channel_caller(in));
5157 
5158  ast_channel_unlock(in);
5160  && !o->block_connected_update) {
5161  struct ast_party_redirecting redirecting;
5162 
5163  /*
5164  * Redirecting updates to the caller make sense only on single
5165  * call at a time strategies.
5166  *
5167  * We must unlock o->chan before calling
5168  * ast_channel_redirecting_macro, because we put o->chan into
5169  * autoservice there. That is pretty much a guaranteed
5170  * deadlock. This is why the handling of o->chan's lock may
5171  * seem a bit unusual here.
5172  */
5173  ast_party_redirecting_init(&redirecting);
5176  if (ast_channel_redirecting_sub(o->chan, in, &redirecting, 0) &&
5177  ast_channel_redirecting_macro(o->chan, in, &redirecting, 1, 0)) {
5178  ast_channel_update_redirecting(in, &redirecting, NULL);
5179  }
5180  ast_party_redirecting_free(&redirecting);
5181  } else {
5183  }
5184 
5185  if (ast_call(o->chan, stuff, 0)) {
5186  ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n",
5187  tech, stuff);
5188  failed = 1;
5189  }
5190  }
5191 
5192  ast_channel_publish_dial_forward(qe->chan, original, o->chan, NULL,
5193  "CANCEL", ast_channel_call_forward(original));
5194  if (o->chan) {
5195  ast_channel_publish_dial(qe->chan, o->chan, stuff, NULL);
5196  }
5197 
5198  if (failed) {
5199  do_hang(o);
5200  numnochan++;
5201  }
5202 
5203  /* Hangup the original channel now, in case we needed it */
5204  ast_hangup(winner);
5205  continue;
5206  }
5207  f = ast_read(winner);
5208  if (f) {
5209  if (f->frametype == AST_FRAME_CONTROL) {
5210  switch (f->subclass.integer) {
5211  case AST_CONTROL_ANSWER:
5212  /* This is our guy if someone answered. */
5213  if (!peer) {
5214  ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
5215  ast_channel_publish_dial(qe->chan, o->chan, on, "ANSWER");
5216  publish_dial_end_event(qe->chan, outgoing, o->chan, "CANCEL");
5217  if (o->orig_chan_name
5218  && strcmp(o->orig_chan_name, ochan_name)) {
5219  /*
5220  * The channel name changed so we must generate COLP update.
5221  * Likely because a call pickup channel masqueraded in.
5222  */
5224  } else if (!o->block_connected_update) {
5225  if (o->pending_connected_update) {
5226  if (ast_channel_connected_line_sub(o->chan, in, &o->connected, 0) &&
5227  ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
5229  }
5230  } else if (!o->dial_callerid_absent) {
5232  }
5233  }
5234  if (o->aoc_s_rate_list) {
5235  size_t encoded_size;
5236  struct ast_aoc_encoded *encoded;
5237  if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
5238  ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
5239  ast_aoc_destroy_encoded(encoded);
5240  }
5241  }
5242  peer = o;
5243  }
5244  break;
5245  case AST_CONTROL_BUSY:
5246  ast_verb(3, "%s is busy\n", ochan_name);
5247  ast_channel_publish_dial(qe->chan, o->chan, on, "BUSY");
5248  endtime = (long) time(NULL);
5249  endtime -= starttime;
5250  rna(endtime * 1000, qe, o->chan, on, membername, qe->parent->autopausebusy);
5251  do_hang(o);
5252  if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
5253  if (qe->parent->timeoutrestart) {
5254  start_time_tv = ast_tvnow();
5255  }
5256  /* Have enough time for a queue member to answer? */
5257  if (ast_remaining_ms(start_time_tv, orig) > 500) {
5258  ring_one(qe, outgoing, &numbusies);
5259  starttime = (long) time(NULL);
5260  }
5261  }
5262  numbusies++;
5263  break;
5265  ast_verb(3, "%s is circuit-busy\n", ochan_name);
5266  ast_channel_publish_dial(qe->chan, o->chan, on, "CONGESTION");
5267  endtime = (long) time(NULL);
5268  endtime -= starttime;
5269  rna(endtime * 1000, qe, o->chan, on, membername, qe->parent->autopauseunavail);
5270  do_hang(o);
5271  if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
5272  if (qe->parent->timeoutrestart) {
5273  start_time_tv = ast_tvnow();
5274  }
5275  if (ast_remaining_ms(start_time_tv, orig) > 500) {
5276  ring_one(qe, outgoing, &numbusies);
5277  starttime = (long) time(NULL);
5278  }
5279  }
5280  numbusies++;
5281  break;
5282  case AST_CONTROL_RINGING:
5283  ast_verb(3, "%s is ringing\n", ochan_name);
5284 
5285  ast_channel_publish_dial(qe->chan, o->chan, on, "RINGING");
5286 
5287  /* Start ring indication when the channel is ringing, if specified */
5288  if (qe->ring_when_ringing) {
5289  ast_moh_stop(qe->chan);
5291  }
5292  break;
5293  case AST_CONTROL_OFFHOOK:
5294  /* Ignore going off hook */
5295  break;
5297  if (o->block_connected_update) {
5298  ast_verb(3, "Connected line update to %s prevented.\n", inchan_name);
5299  break;
5300  }
5301  if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
5302  struct ast_party_connected_line connected;
5303 
5304  ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ochan_name, inchan_name);
5306  ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected);
5307  ast_party_connected_line_set(&o->connected, &connected, NULL);
5308  ast_party_connected_line_free(&connected);
5309  o->pending_connected_update = 1;
5310  break;
5311  }
5312 
5313  /*
5314  * Prevent using the CallerID from the outgoing channel since we
5315  * got a connected line update from it.
5316  */
5317  o->dial_callerid_absent = 1;
5318 
5319  if (ast_channel_connected_line_sub(o->chan, in, f, 1) &&
5320  ast_channel_connected_line_macro(o->chan, in, f, 1, 1)) {
5322  }
5323  break;
5324  case AST_CONTROL_AOC:
5325  {
5326  struct ast_aoc_decoded *decoded = ast_aoc_decode(f->data.ptr, f->datalen, o->chan);
5327  if (decoded && (ast_aoc_get_msg_type(decoded) == AST_AOC_S)) {
5329  o->aoc_s_rate_list = decoded;
5330  } else {
5331  ast_aoc_destroy_decoded(decoded);
5332  }
5333  }
5334  break;
5336  if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
5337  /*
5338  * Redirecting updates to the caller make sense only on single
5339  * call at a time strategies.
5340  */
5341  break;
5342  }
5343  if (o->block_connected_update) {
5344  ast_verb(3, "Redirecting update to %s prevented\n",
5345  inchan_name);
5346  break;
5347  }
5348  ast_verb(3, "%s redirecting info has changed, passing it to %s\n",
5349  ochan_name, inchan_name);
5350  if (ast_channel_redirecting_sub(o->chan, in, f, 1) &&
5351  ast_channel_redirecting_macro(o->chan, in, f, 1, 1)) {
5353  }
5354  break;
5357  break;
5358  default:
5359  ast_debug(1, "Dunno what to do with control type %d\n", f->subclass.integer);
5360  break;
5361  }
5362  }
5363  ast_frfree(f);
5364  } else { /* ast_read() returned NULL */
5365  endtime = (long) time(NULL) - starttime;
5366  ast_channel_publish_dial(qe->chan, o->chan, on, "NOANSWER");
5367  rna(endtime * 1000, qe, o->chan, on, membername, 1);
5368  do_hang(o);
5369  if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
5370  if (qe->parent->timeoutrestart) {
5371  start_time_tv = ast_tvnow();
5372  }
5373  if (ast_remaining_ms(start_time_tv, orig) > 500) {
5374  ring_one(qe, outgoing, &numbusies);
5375  starttime = (long) time(NULL);
5376  }
5377  }
5378  }
5379  }
5380  }
5381 
5382  /* If we received an event from the caller, deal with it. */
5383  if (winner == in) {
5384  f = ast_read(in);
5385  if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) {
5386  /* Got hung up */
5387  *to = -1;
5388  if (f) {
5389  if (f->data.uint32) {
5391  }
5392  ast_frfree(f);
5393  }
5394  canceled_by_caller = 1;
5395  } else if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) {
5396  ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
5397  *to = 0;
5398  ast_frfree(f);
5399  canceled_by_caller = 1;
5400  } else if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass.integer)) {
5401  ast_verb(3, "User pressed digit: %c\n", f->subclass.integer);
5402  *to = 0;
5403  *digit = f->subclass.integer;
5404  ast_frfree(f);
5405  canceled_by_caller = 1;
5406  }
5407  /* When caller hung up or pressed * or digit. */
5408  if (canceled_by_caller) {
5409  publish_dial_end_event(in, outgoing, NULL, "CANCEL");
5410  for (o = start; o; o = o->call_next) {
5411  if (o->chan) {
5412  ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), o->member->membername, "RINGCANCELED", "%d", (int) ast_tvdiff_ms(ast_tvnow(), start_time_tv));
5413  }
5414  }
5415  return NULL;
5416  }
5417 
5418  /* Send the frame from the in channel to all outgoing channels. */
5419  for (o = start; o; o = o->call_next) {
5420  if (!o->stillgoing || !o->chan) {
5421  /* This outgoing channel has died so don't send the frame to it. */
5422  continue;
5423  }
5424  switch (f->frametype) {
5425  case AST_FRAME_CONTROL:
5426  switch (f->subclass.integer) {
5428  if (o->block_connected_update) {
5429  ast_verb(3, "Connected line update to %s prevented.\n", ast_channel_name(o->chan));
5430  break;
5431  }
5432  if (ast_channel_connected_line_sub(in, o->chan, f, 1) &&
5433  ast_channel_connected_line_macro(in, o->chan, f, 0, 1)) {
5435  }
5436  break;
5438  if (o->block_connected_update) {
5439  ast_verb(3, "Redirecting update to %s prevented.\n", ast_channel_name(o->chan));
5440  break;
5441  }
5442  if (ast_channel_redirecting_sub(in, o->chan, f, 1) &&
5443  ast_channel_redirecting_macro(in, o->chan, f, 0, 1)) {
5445  }
5446  break;
5447  default:
5448  /* We are not going to do anything with this frame. */
5449  goto skip_frame;
5450  }
5451  break;
5452  default:
5453  /* We are not going to do anything with this frame. */
5454  goto skip_frame;
5455  }
5456  }
5457 skip_frame:;
5458 
5459  ast_frfree(f);
5460  }
5461  }
5462 
5463  if (!*to) {
5464  for (o = start; o; o = o->call_next) {
5465  if (o->chan) {
5466  rna(orig, qe, o->chan, o->interface, o->member->membername, 1);
5467  }
5468  }
5469 
5470  publish_dial_end_event(qe->chan, outgoing, NULL, "NOANSWER");
5471  }
5472 
5473  return peer;
5474 }
5475 
5476 /*!
5477  * \brief Check if we should start attempting to call queue members.
5478  *
5479  * A simple process, really. Count the number of members who are available
5480  * to take our call and then see if we are in a position in the queue at
5481  * which a member could accept our call.
5482  *
5483  * \param[in] qe The caller who wants to know if it is his turn
5484  * \retval 0 It is not our turn
5485  * \retval 1 It is our turn
5486  */
5487 static int is_our_turn(struct queue_ent *qe)
5488 {
5489  struct queue_ent *ch;
5490  int res;
5491  int avl;
5492  int idx = 0;
5493  /* This needs a lock. How many members are available to be served? */
5494  ao2_lock(qe->parent);
5495 
5496  avl = num_available_members(qe->parent);
5497 
5498  ch = qe->parent->head;
5499 
5500  ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member");
5501 
5502  while ((idx < avl) && (ch) && (ch != qe)) {
5503  if (!ch->pending) {
5504  idx++;
5505  }
5506  ch = ch->next;
5507  }
5508 
5509  ao2_unlock(qe->parent);
5510  /* If the queue entry is within avl [the number of available members] calls from the top ...
5511  * Autofill and position check added to support autofill=no (as only calls
5512  * from the front of the queue are valid when autofill is disabled)
5513  */
5514  if (ch && idx < avl && (qe->parent->autofill || qe->pos == 1)) {
5515  ast_debug(1, "It's our turn (%s).\n", ast_channel_name(qe->chan));
5516  res = 1;
5517  } else {
5518  ast_debug(1, "It's not our turn (%s).\n", ast_channel_name(qe->chan));
5519  res = 0;
5520  }
5521 
5522  /* Update realtime members if this is the first call and number of avalable members is 0 */
5523  if (avl == 0 && qe->pos == 1) {
5525  }
5526 
5527  return res;
5528 }
5529 
5530 /*!
5531  * \brief update rules for queues
5532  *
5533  * Calculate min/max penalties making sure if relative they stay within bounds.
5534  * Update queues penalty and set dialplan vars, goto next list entry.
5535 */
5536 static void update_qe_rule(struct queue_ent *qe)
5537 {
5538  int max_penalty = INT_MAX;
5539 
5540  if (qe->max_penalty != INT_MAX) {
5541  char max_penalty_str[20];
5542 
5543  if (qe->pr->max_relative) {
5544  max_penalty = qe->max_penalty + qe->pr->max_value;
5545  } else {
5546  max_penalty = qe->pr->max_value;
5547  }
5548 
5549  /* a relative change to the penalty could put it below 0 */
5550  if (max_penalty < 0) {
5551  max_penalty = 0;
5552  }
5553 
5554  snprintf(max_penalty_str, sizeof(max_penalty_str), "%d", max_penalty);
5555  pbx_builtin_setvar_helper(qe->chan, "QUEUE_MAX_PENALTY", max_penalty_str);
5556  qe->max_penalty = max_penalty;
5557  ast_debug(3, "Setting max penalty to %d for caller %s since %d seconds have elapsed\n",
5558  qe->max_penalty, ast_channel_name(qe->chan), qe->pr->time);
5559  }
5560 
5561  if (qe->min_penalty != INT_MAX) {
5562  char min_penalty_str[20];
5563  int min_penalty;
5564 
5565  if (qe->pr->min_relative) {
5566  min_penalty = qe->min_penalty + qe->pr->min_value;
5567  } else {
5568  min_penalty = qe->pr->min_value;
5569  }
5570 
5571  /* a relative change to the penalty could put it below 0 */
5572  if (min_penalty < 0) {
5573  min_penalty = 0;
5574  }
5575 
5576  if (max_penalty != INT_MAX && min_penalty > max_penalty) {
5577  min_penalty = max_penalty;
5578  }
5579 
5580  snprintf(min_penalty_str, sizeof(min_penalty_str), "%d", min_penalty);
5581  pbx_builtin_setvar_helper(qe->chan, "QUEUE_MIN_PENALTY", min_penalty_str);
5582  qe->min_penalty = min_penalty;
5583  ast_debug(3, "Setting min penalty to %d for caller %s since %d seconds have elapsed\n",
5584  qe->min_penalty, ast_channel_name(qe->chan), qe->pr->time);
5585  }
5586 
5587  if (qe->raise_penalty != INT_MAX) {
5588  char raise_penalty_str[20];
5589  int raise_penalty;
5590 
5591  if (qe->pr->raise_relative) {
5592  raise_penalty = qe->raise_penalty + qe->pr->raise_value;
5593  } else {
5594  raise_penalty = qe->pr->raise_value;
5595  }
5596 
5597  /* a relative change to the penalty could put it below 0 */
5598  if (raise_penalty < 0) {
5599  raise_penalty = 0;
5600  }
5601 
5602  if (max_penalty != INT_MAX && raise_penalty > max_penalty) {
5603  raise_penalty = max_penalty;
5604  }
5605 
5606  snprintf(raise_penalty_str, sizeof(raise_penalty_str), "%d", raise_penalty);
5607  pbx_builtin_setvar_helper(qe->chan, "QUEUE_RAISE_PENALTY", raise_penalty_str);
5609  ast_debug(3, "Setting raised penalty to %d for caller %s since %d seconds have elapsed\n",
5610  qe->raise_penalty, ast_channel_name(qe->chan), qe->pr->time);
5611  }
5612 
5613  qe->pr = AST_LIST_NEXT(qe->pr, list);
5614 }
5615 
5616 /*! \brief The waiting areas for callers who are not actively calling members
5617  *
5618  * This function is one large loop. This function will return if a caller
5619  * either exits the queue or it becomes that caller's turn to attempt calling
5620  * queue members. Inside the loop, we service the caller with periodic announcements,
5621  * holdtime announcements, etc. as configured in queues.conf
5622  *
5623  * \retval 0 if the caller's turn has arrived
5624  * \retval -1 if the caller should exit the queue.
5625  */
5626 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
5627 {
5628  int res = 0;
5629 
5630  /* This is the holding pen for callers 2 through maxlen */
5631  for (;;) {
5632 
5633  if (is_our_turn(qe)) {
5634  break;
5635  }
5636 
5637  /* If we have timed out, break out */
5638  if (qe->expire && (time(NULL) >= qe->expire)) {
5639  *reason = QUEUE_TIMEOUT;
5640  break;
5641  }
5642 
5643  if (qe->parent->leavewhenempty) {
5644  int status = 0;
5645 
5646  if ((status = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty, qe->raise_penalty, qe->parent->leavewhenempty, 0))) {
5647  record_abandoned(qe);
5648  *reason = QUEUE_LEAVEEMPTY;
5649  ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) (time(NULL) - qe->start));
5650  res = -1;
5651  qe->handled = -1;
5652  break;
5653  }
5654  }
5655 
5656  /* Make a position announcement, if enabled */
5657  if (qe->parent->announcefrequency &&
5658  (res = say_position(qe,ringing))) {
5659  break;
5660  }
5661 
5662  /* If we have timed out, break out */
5663  if (qe->expire && (time(NULL) >= qe->expire)) {
5664  *reason = QUEUE_TIMEOUT;
5665  break;
5666  }
5667 
5668  /* Make a periodic announcement, if enabled */
5669  if (qe->parent->periodicannouncefrequency &&
5670  (res = say_periodic_announcement(qe,ringing)))
5671  break;
5672 
5673  /* see if we need to move to the next penalty level for this queue */
5674  while (qe->pr && ((time(NULL) - qe->start) >= qe->pr->time)) {
5675  update_qe_rule(qe);
5676  }
5677 
5678  /* If we have timed out, break out */
5679  if (qe->expire && (time(NULL) >= qe->expire)) {
5680  *reason = QUEUE_TIMEOUT;
5681  break;
5682  }
5683 
5684  /* Wait a second before checking again */
5685  if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
5686  if (res > 0 && !valid_exit(qe, res)) {
5687  res = 0;
5688  } else {
5689  break;
5690  }
5691  }
5692 
5693  /* If we have timed out, break out */
5694  if (qe->expire && (time(NULL) >= qe->expire)) {
5695  *reason = QUEUE_TIMEOUT;
5696  break;
5697  }
5698  }
5699 
5700  return res;
5701 }
5702 
5703 /*!
5704  * \brief update the queue status
5705  * \retval Always 0
5706 */
5707 static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime)
5708 {
5709  int oldtalktime;
5710  int newtalktime = time(NULL) - starttime;
5711  struct member *mem;
5712  struct call_queue *qtmp;
5713  struct ao2_iterator queue_iter;
5714 
5715  /* It is possible for us to be called when a call has already been considered terminated
5716  * and data updated, so to ensure we only act on the call that the agent is currently in
5717  * we check when the call was bridged.
5718  */
5719  if (!starttime || (member->starttime != starttime)) {
5720  return 0;
5721  }
5722 
5723  if (shared_lastcall) {
5724  queue_iter = ao2_iterator_init(queues, 0);
5725  while ((qtmp = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
5726  ao2_lock(qtmp);
5727  if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) {
5728  time(&mem->lastcall);
5729  mem->calls++;
5730  mem->callcompletedinsl = 0;
5731  mem->starttime = 0;
5732  mem->lastqueue = q;
5733  ao2_ref(mem, -1);
5734  }
5735  ao2_unlock(qtmp);
5736  queue_t_unref(qtmp, "Done with iterator");
5737  }
5738  ao2_iterator_destroy(&queue_iter);
5739  } else {
5740  ao2_lock(q);
5741  time(&member->lastcall);
5742  member->callcompletedinsl = 0;
5743  member->calls++;
5744  member->starttime = 0;
5745  member->lastqueue = q;
5746  ao2_unlock(q);
5747  }
5748  /* Member might never experience any direct status change (local
5749  * channel with forwarding in particular). If that's the case,
5750  * this is the last chance to remove it from pending or subsequent
5751  * calls will not occur.
5752  */
5753  pending_members_remove(member);
5754 
5755  ao2_lock(q);
5756  q->callscompleted++;
5757  if (callcompletedinsl) {
5758  q->callscompletedinsl++;
5759  }
5760  if (q->callscompleted == 1) {
5761  q->talktime = newtalktime;
5762  } else {
5763  /* Calculate talktime using the same exponential average as holdtime code */
5764  oldtalktime = q->talktime;
5765  q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
5766  }
5767  ao2_unlock(q);
5768  return 0;
5769 }
5770 
5771 /*! \brief Calculate the metric of each member in the outgoing callattempts
5772  *
5773  * A numeric metric is given to each member depending on the ring strategy used
5774  * by the queue. Members with lower metrics will be called before members with
5775  * higher metrics
5776  * \retval -1 if penalties are exceeded
5777  * \retval 0 otherwise
5778  */
5779 static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
5780 {
5781  /* disregarding penalty on too few members? */
5782  int membercount = ao2_container_count(q->members);
5783  unsigned char usepenalty = (membercount <= q->penaltymemberslimit) ? 0 : 1;
5784  int penalty = mem->penalty;
5785 
5786  if (usepenalty) {
5787  if (qe->raise_penalty != INT_MAX && penalty < qe->raise_penalty) {
5788  /* Low penalty is raised up to the current minimum */
5789  penalty = qe->raise_penalty;
5790  }
5791  if ((qe->max_penalty != INT_MAX && penalty > qe->max_penalty) ||
5792  (qe->min_penalty != INT_MAX && penalty < qe->min_penalty)) {
5793  return -1;
5794  }
5795  } else {
5796  ast_debug(1, "Disregarding penalty, %d members and %d in penaltymemberslimit.\n",
5797  membercount, q->penaltymemberslimit);
5798  }
5799 
5800  switch (q->strategy) {
5802  /* Everyone equal, except for penalty */
5803  tmp->metric = penalty * 1000000 * usepenalty;
5804  break;
5805  case QUEUE_STRATEGY_LINEAR:
5806  if (pos < qe->linpos) {
5807  tmp->metric = 1000 + pos;
5808  } else {
5809  if (pos > qe->linpos) {
5810  /* Indicate there is another priority */
5811  qe->linwrapped = 1;
5812  }
5813  tmp->metric = pos;
5814  }
5815  tmp->metric += penalty * 1000000 * usepenalty;
5816  break;
5819  pos = mem->queuepos;
5820  if (pos < q->rrpos) {
5821  tmp->metric = 1000 + pos;
5822  } else {
5823  if (pos > q->rrpos) {
5824  /* Indicate there is another priority */
5825  q->wrapped = 1;
5826  }
5827  tmp->metric = pos;
5828  }
5829  tmp->metric += penalty * 1000000 * usepenalty;
5830  break;
5831  case QUEUE_STRATEGY_RANDOM:
5832  tmp->metric = ast_random() % 1000;
5833  tmp->metric += penalty * 1000000 * usepenalty;
5834  break;
5836  tmp->metric = ast_random() % ((1 + penalty) * 1000);
5837  break;
5839  tmp->metric = mem->calls;
5840  tmp->metric += penalty * 1000000 * usepenalty;
5841  break;
5843  if (!mem->lastcall) {
5844  tmp->metric = 0;
5845  } else {
5846  tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
5847  }
5848  tmp->metric += penalty * 1000000 * usepenalty;
5849  break;
5850  default:
5851  ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
5852  break;
5853  }
5854  return 0;
5855 }
5856 
5861 };
5862 
5863 /*! \brief Send out AMI message with member call completion status information */
5864 static void send_agent_complete(const char *queuename, struct ast_channel_snapshot *caller,
5865  struct ast_channel_snapshot *peer, const struct member *member, time_t holdstart,
5866  time_t callstart, enum agent_complete_reason rsn)
5867 {
5868  const char *reason = NULL; /* silence dumb compilers */
5869  RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
5870 
5871  switch (rsn) {
5872  case CALLER:
5873  reason = "caller";
5874  break;
5875  case AGENT:
5876  reason = "agent";
5877  break;
5878  case TRANSFER:
5879  reason = "transfer";
5880  break;
5881  }
5882 
5883  blob = ast_json_pack("{s: s, s: s, s: s, s: I, s: I, s: s}",
5884  "Queue", queuename,
5885  "Interface", member->interface,
5886  "MemberName", member->membername,
5887  "HoldTime", (ast_json_int_t)(callstart - holdstart),
5888  "TalkTime", (ast_json_int_t)(time(NULL) - callstart),
5889  "Reason", reason ?: "");
5890 
5892  queue_agent_complete_type(), blob);
5893 }
5894 
5895 static void queue_agent_cb(void *userdata, struct stasis_subscription *sub,
5896  struct stasis_message *msg)
5897 {
5898  struct ast_channel_blob *agent_blob;
5899 
5900  agent_blob = stasis_message_data(msg);
5901 
5903  ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
5904  ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
5905  "AGENTLOGIN", "%s", agent_blob->snapshot->base->name);
5906  } else if (ast_channel_agent_logoff_type() == stasis_message_type(msg)) {
5907  ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
5908  ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
5909  "AGENTLOGOFF", "%s|%ld", agent_blob->snapshot->base->name,
5910  (long) ast_json_integer_get(ast_json_object_get(agent_blob->blob, "logintime")));
5911  }
5912 }
5913 
5914 /*!
5915  * \brief Structure representing relevant data during a local channel optimization
5916  *
5917  * The reason we care about local channel optimizations is that we want to be able
5918  * to accurately report when the caller and queue member have stopped talking to
5919  * each other. A local channel optimization can cause it to appear that the conversation
5920  * has stopped immediately after it has begun. By tracking that the relevant channels
5921  * to monitor have changed due to a local channel optimization, we can give accurate
5922  * reports.
5923  *
5924  * Local channel optimizations for queues are restricted from their normal operation.
5925  * Bridges created by queues can only be the destination of local channel optimizations,
5926  * not the source. In addition, move-swap local channel optimizations are the only
5927  * permitted types of local channel optimization.
5928  *
5929  * This data is populated when we are told that a local channel optimization begin
5930  * is occurring. When we get told the optimization has ended successfully, we then
5931  * apply the data here into the queue_stasis_data.
5932  */
5934  /*! The uniqueid of the channel that will be taking the place of the caller or member */
5936  /*! Indication of whether we think there is a local channel optimization in progress */
5938  /*! The identifier for this local channel optimization */
5939  unsigned int id;
5940 };
5941 
5942 /*!
5943  * \brief User data for stasis subscriptions used for queue calls.
5944  *
5945  * app_queue subscribes to channel and bridge events for all bridged calls.
5946  * app_queue cares about the following events:
5947  *
5948  * \li bridge enter: To determine the unique ID of the bridge created for the call.
5949  * \li blind transfer: To send an appropriate agent complete event.
5950  * \li attended transfer: To send an appropriate agent complete event.
5951  * \li local optimization: To update caller and member unique IDs for the call.
5952  * \li hangup: To send an appropriate agent complete event.
5953  *
5954  * The stasis subscriptions last until we determine that the caller and the member
5955  * are no longer bridged with each other.
5956  */
5959  /*! The unique ID of the caller's channel. */
5960  AST_STRING_FIELD(caller_uniqueid);
5961  /*! The unique ID of the queue member's channel */
5962  AST_STRING_FIELD(member_uniqueid);
5963  /*! The unique ID of the bridge created by the queue */
5964  AST_STRING_FIELD(bridge_uniqueid);
5965  );
5966  /*! The relevant queue */
5968  /*! The queue member that has answered the call */
5969  struct member *member;
5970  /*! The time at which the caller entered the queue. Start of the caller's hold time */
5971  time_t holdstart;
5972  /*! The time at which the member answered the call. */
5973  time_t starttime;
5974  /*! The original position of the caller when he entered the queue */
5976  /*! Indication if the call was answered within the configured service level of the queue */
5978  /*! Indicates if the stasis subscriptions are shutting down */
5979  int dying;
5980  /*! The stasis message router for bridge events */
5982  /*! The stasis message router for channel events */
5984  /*! Local channel optimization details for the caller */
5985  struct local_optimization caller_optimize;
5986  /*! Local channel optimization details for the member */
5987  struct local_optimization member_optimize;
5988 };
5989 
5990 /*!
5991  * \internal
5992  * \brief Free memory for a queue_stasis_data
5993  */
5994 static void queue_stasis_data_destructor(void *obj)
5995 {
5996  struct queue_stasis_data *queue_data = obj;
5997 
5998  /* This can only happen if refcounts for this object have got severely messed up */
5999  ast_assert(queue_data->bridge_router == NULL);
6000  ast_assert(queue_data->channel_router == NULL);
6001 
6002  ao2_cleanup(queue_data->member);
6003  queue_unref(queue_data->queue);
6004  ast_string_field_free_memory(queue_data);
6005 }
6006 
6007 /*!
6008  * \internal
6009  * \brief End all stasis subscriptions on a queue_stasis_data
6010  */
6011 static void remove_stasis_subscriptions(struct queue_stasis_data *queue_data)
6012 {
6013  SCOPED_AO2LOCK(lock, queue_data);
6014 
6015  queue_data->dying = 1;
6017  queue_data->bridge_router = NULL;
6019  queue_data->channel_router = NULL;
6020 }
6021 
6022 /*!
6023  * \internal
6024  * \brief Allocate a queue_stasis_data and initialize its data.
6025  */
6027  struct ast_channel *peer, struct member *mem, time_t holdstart,
6028  time_t starttime, int callcompletedinsl)
6029 {
6030  struct queue_stasis_data *queue_data;
6031 
6032  queue_data = ao2_alloc(sizeof(*queue_data), queue_stasis_data_destructor);
6033  if (!queue_data) {
6034  return NULL;
6035  }
6036 
6037  if (ast_string_field_init(queue_data, 64)) {
6038  ao2_cleanup(queue_data);
6039  return NULL;
6040  }
6041 
6044  queue_data->queue = queue_ref(qe->parent);
6045  queue_data->starttime = starttime;
6046  queue_data->holdstart = holdstart;
6047  queue_data->callcompletedinsl = callcompletedinsl;
6048  queue_data->caller_pos = qe->opos;
6049  ao2_ref(mem, +1);
6050  queue_data->member = mem;
6051 
6052  return queue_data;
6053 }
6054 
6055 /*!
6056  * \internal
6057  * \brief Log an attended transfer in the queue log.
6058  *
6059  * Attended transfer queue log messages vary based on the method by which the
6060  * attended transfer was completed.
6061  *
6062  * \param queue_data Data pertaining to the particular call in the queue.
6063  * \param atxfer_msg The stasis attended transfer message data.
6064  */
6065 static void log_attended_transfer(struct queue_stasis_data *queue_data,
6066  struct ast_attended_transfer_message *atxfer_msg)
6067 {
6068  RAII_VAR(struct ast_str *, transfer_str, ast_str_create(32), ast_free);
6069 
6070  if (!transfer_str) {
6071  ast_log(LOG_WARNING, "Unable to log attended transfer to queue log\n");
6072  return;
6073  }
6074 
6075  switch (atxfer_msg->dest_type) {
6077  ast_str_set(&transfer_str, 0, "BRIDGE|%s", atxfer_msg->dest.bridge);
6078  break;
6081  ast_str_set(&transfer_str, 0, "APP|%s", atxfer_msg->dest.app);
6082  break;
6084  ast_str_set(&transfer_str, 0, "LINK|%s|%s", atxfer_msg->dest.links[0]->base->name,
6085  atxfer_msg->dest.links[1]->base->name);
6086  break;
6089  /* Threeways are headed off and should not be logged here */
6090  ast_assert(0);
6091  return;
6092  }
6093 
6094  ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername, "ATTENDEDTRANSFER", "%s|%ld|%ld|%d",
6095  ast_str_buffer(transfer_str),
6096  (long) (queue_data->starttime - queue_data->holdstart),
6097  (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6098 }
6099 
6100 /*!
6101  * \internal
6102  * \brief Handle a stasis bridge enter event.
6103  *
6104  * We track this particular event in order to learn what bridge
6105  * was created for the queue call.
6106  *
6107  * \param userdata Data pertaining to the particular call in the queue.
6108  * \param sub The stasis subscription on which the message occurred.
6109  * \param topic The topic for this event.
6110  * \param msg The stasis message for the bridge enter event
6111  */
6112 static void handle_bridge_enter(void *userdata, struct stasis_subscription *sub,
6113  struct stasis_message *msg)
6114 {
6115  struct queue_stasis_data *queue_data = userdata;
6116  struct ast_bridge_blob *enter_blob = stasis_message_data(msg);
6117  SCOPED_AO2LOCK(lock, queue_data);
6118 
6119  if (queue_data->dying) {
6120  return;
6121  }
6122 
6123  if (!ast_strlen_zero(queue_data->bridge_uniqueid)) {
6124  return;
6125  }
6126 
6127  if (!strcmp(enter_blob->channel->base->uniqueid, queue_data->caller_uniqueid)) {
6128  ast_string_field_set(queue_data, bridge_uniqueid,
6129  enter_blob->bridge->uniqueid);
6130  ast_debug(3, "Detected entry of caller channel %s into bridge %s\n",
6131  enter_blob->channel->base->name, queue_data->bridge_uniqueid);
6132  }
6133 }
6134 
6135 /*!
6136  * \brief Handle a blind transfer event
6137  *
6138  * This event is important in order to be able to log the end of the
6139  * call to the queue log and to stasis.
6140  *
6141  * \param userdata Data pertaining to the particular call in the queue.
6142  * \param sub The stasis subscription on which the message occurred.
6143  * \param topic The topic for this event.
6144  * \param msg The stasis message for the blind transfer event
6145  */
6146 static void handle_blind_transfer(void *userdata, struct stasis_subscription *sub,
6147  struct stasis_message *msg)
6148 {
6149  struct queue_stasis_data *queue_data = userdata;
6150  struct ast_blind_transfer_message *transfer_msg = stasis_message_data(msg);
6151  const char *exten;
6152  const char *context;
6153  RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6154  RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6155 
6156  if (transfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS) {
6157  return;
6158  }
6159 
6160  ao2_lock(queue_data);
6161 
6162  if (queue_data->dying) {
6163  ao2_unlock(queue_data);
6164  return;
6165  }
6166 
6167  if (ast_strlen_zero(queue_data->bridge_uniqueid) ||
6168  strcmp(queue_data->bridge_uniqueid, transfer_msg->bridge->uniqueid)) {
6169  ao2_unlock(queue_data);
6170  return;
6171  }
6172 
6173  caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6174  member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6175 
6176  ao2_unlock(queue_data);
6177 
6178  exten = transfer_msg->exten;
6179  context = transfer_msg->context;
6180 
6181  ast_debug(3, "Detected blind transfer in queue %s\n", queue_data->queue->name);
6182  ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername,
6183  "BLINDTRANSFER", "%s|%s|%ld|%ld|%d",
6184  exten, context,
6185  (long) (queue_data->starttime - queue_data->holdstart),
6186  (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6187 
6188  send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6189  queue_data->holdstart, queue_data->starttime, TRANSFER);
6190  update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6191  queue_data->starttime);
6192  remove_stasis_subscriptions(queue_data);
6193 }
6194 
6195 /*!
6196  * \brief Handle an attended transfer event
6197  *
6198  * This event is important in order to be able to log the end of the
6199  * call to the queue log and to stasis.
6200  *
6201  * \param userdata Data pertaining to the particular call in the queue.
6202  * \param sub The stasis subscription on which the message occurred.
6203  * \param topic The topic for this event.
6204  * \param msg The stasis message for the attended transfer event.
6205  */
6206 static void handle_attended_transfer(void *userdata, struct stasis_subscription *sub,
6207  struct stasis_message *msg)
6208 {
6209  struct queue_stasis_data *queue_data = userdata;
6210  struct ast_attended_transfer_message *atxfer_msg = stasis_message_data(msg);
6211  RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6212  RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6213 
6214  if (atxfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS ||
6216  return;
6217  }
6218 
6219  ao2_lock(queue_data);
6220 
6221  if (queue_data->dying) {
6222  ao2_unlock(queue_data);
6223  return;
6224  }
6225 
6226  if (ast_strlen_zero(queue_data->bridge_uniqueid)) {
6227  ao2_unlock(queue_data);
6228  return;
6229  }
6230 
6231  if ((!atxfer_msg->to_transferee.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
6232  atxfer_msg->to_transferee.bridge_snapshot->uniqueid)) &&
6233  (!atxfer_msg->to_transfer_target.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
6234  atxfer_msg->to_transfer_target.bridge_snapshot->uniqueid))) {
6235  ao2_unlock(queue_data);
6236  return;
6237  }
6238 
6239  caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6240  member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6241 
6242  ao2_unlock(queue_data);
6243 
6244  ast_debug(3, "Detected attended transfer in queue %s\n", queue_data->queue->name);
6245  log_attended_transfer(queue_data, atxfer_msg);
6246 
6247  send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6248  queue_data->holdstart, queue_data->starttime, TRANSFER);
6249  update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6250  queue_data->starttime);
6251  remove_stasis_subscriptions(queue_data);
6252 }
6253 
6254 /*!
6255  * \internal
6256  * \brief Callback for all stasis bridge events
6257  *
6258  * Based on the event and what bridge it is on, the task is farmed out to relevant
6259  * subroutines for further processing.
6260  */
6261 static void queue_bridge_cb(void *userdata, struct stasis_subscription *sub,
6262  struct stasis_message *msg)
6263 {
6264  if (stasis_subscription_final_message(sub, msg)) {
6265  ao2_cleanup(userdata);
6266  }
6267 }
6268 
6269 /*!
6270  * \internal
6271  * \brief Handler for the beginning of a local channel optimization
6272  *
6273  * This method gathers data relevant to the local channel optimization and stores
6274  * it to be used once the local optimization completes.
6275  *
6276  * \param userdata Data pertaining to the particular call in the queue.
6277  * \param sub The stasis subscription on which the message occurred.
6278  * \param topic The topic for this event.
6279  * \param msg The stasis message for the local optimization begin event
6280  */
6281 static void handle_local_optimization_begin(void *userdata, struct stasis_subscription *sub,
6282  struct stasis_message *msg)
6283 {
6284  struct queue_stasis_data *queue_data = userdata;
6285  struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
6286  struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
6287  struct ast_channel_snapshot *local_two = ast_multi_channel_blob_get_channel(optimization_blob, "2");
6288  struct ast_channel_snapshot *source = ast_multi_channel_blob_get_channel(optimization_blob, "source");
6289  struct local_optimization *optimization;
6290  unsigned int id;
6291  SCOPED_AO2LOCK(lock, queue_data);
6292 
6293  if (queue_data->dying) {
6294  return;
6295  }
6296 
6297  if (!strcmp(local_one->base->uniqueid, queue_data->member_uniqueid)) {
6298  optimization = &queue_data->member_optimize;
6299  } else if (!strcmp(local_two->base->uniqueid, queue_data->caller_uniqueid)) {
6300  optimization = &queue_data->caller_optimize;
6301  } else {
6302  return;
6303  }
6304 
6305  /* We only allow move-swap optimizations, so there had BETTER be a source */
6306  ast_assert(source != NULL);
6307 
6308  optimization->source_chan_uniqueid = ast_strdup(source->base->uniqueid);
6309  if (!optimization->source_chan_uniqueid) {
6310  ast_log(LOG_ERROR, "Unable to track local channel optimization for channel %s. Expect further errors\n", local_one->base->name);
6311  return;
6312  }
6314 
6315  optimization->id = id;
6316  optimization->in_progress = 1;
6317 }
6318 
6319 /*!
6320  * \internal
6321  * \brief Handler for the end of a local channel optimization
6322  *
6323  * This method takes the data gathered during the local channel optimization begin
6324  * event and applies it to the queue stasis data appropriately. This generally involves
6325  * updating the caller or member unique ID with the channel that is taking the place of
6326  * the previous caller or member.
6327  *
6328  * \param userdata Data pertaining to the particular call in the queue.
6329  * \param sub The stasis subscription on which the message occurred.
6330  * \param topic The topic for this event.
6331  * \param msg The stasis message for the local optimization end event
6332  */
6333 static void handle_local_optimization_end(void *userdata, struct stasis_subscription *sub,
6334  struct stasis_message *msg)
6335 {
6336  struct queue_stasis_data *queue_data = userdata;
6337  struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
6338  struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
6339  struct ast_channel_snapshot *local_two = ast_multi_channel_blob_get_channel(optimization_blob, "2");
6340  struct local_optimization *optimization;
6341  int is_caller;
6342  unsigned int id;
6343  SCOPED_AO2LOCK(lock, queue_data);
6344 
6345  if (queue_data->dying) {
6346  return;
6347  }
6348 
6349  if (!strcmp(local_one->base->uniqueid, queue_data->member_uniqueid)) {
6350  optimization = &queue_data->member_optimize;
6351  is_caller = 0;
6352  } else if (!strcmp(local_two->base->uniqueid, queue_data->caller_uniqueid)) {
6353  optimization = &queue_data->caller_optimize;
6354  is_caller = 1;
6355  } else {
6356  return;
6357  }
6358 
6360 
6361  if (!optimization->in_progress) {
6362  ast_log(LOG_WARNING, "Told of a local optimization end when we had no previous begin\n");
6363  return;
6364  }
6365 
6366  if (id != optimization->id) {
6367  ast_log(LOG_WARNING, "Local optimization end event ID does not match begin (%u != %u)\n",
6368  id, optimization->id);
6369  return;
6370  }
6371 
6372  if (is_caller) {
6373  ast_debug(3, "Local optimization: Changing queue caller uniqueid from %s to %s\n",
6374  queue_data->caller_uniqueid, optimization->source_chan_uniqueid);
6375  ast_string_field_set(queue_data, caller_uniqueid, optimization->source_chan_uniqueid);
6376  } else {
6377  ast_debug(3, "Local optimization: Changing queue member uniqueid from %s to %s\n",
6378  queue_data->member_uniqueid, optimization->source_chan_uniqueid);
6379  ast_string_field_set(queue_data, member_uniqueid, optimization->source_chan_uniqueid);
6380  }
6381 
6382  optimization->in_progress = 0;
6383 }
6384 
6385 /*!
6386  * \internal
6387  * \brief Handler for hangup stasis event
6388  *
6389  * This is how we determine that the caller or member has hung up and the call
6390  * has ended. An appropriate queue log and stasis message are raised in this
6391  * callback.
6392  *
6393  * \param userdata Data pertaining to the particular call in the queue.
6394  * \param sub The stasis subscription on which the message occurred.
6395  * \param topic The topic for this event.
6396  * \param msg The stasis message for the hangup event.
6397  */
6398 static void handle_hangup(void *userdata, struct stasis_subscription *sub,
6399  struct stasis_message *msg)
6400 {
6401  struct queue_stasis_data *queue_data = userdata;
6402  struct ast_channel_blob *channel_blob = stasis_message_data(msg);
6403  RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6404  RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6405  RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
6406  enum agent_complete_reason reason;
6407 
6408  ao2_lock(queue_data);
6409 
6410  if (queue_data->dying) {
6411  ao2_unlock(queue_data);
6412  return;
6413  }
6414 
6415  if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->caller_uniqueid)) {
6416  reason = CALLER;
6417  } else if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->member_uniqueid)) {
6418  reason = AGENT;
6419  } else {
6420  ao2_unlock(queue_data);
6421  return;
6422  }
6423 
6424  chan = ast_channel_get_by_name(channel_blob->snapshot->base->name);
6425  if (chan && (ast_channel_has_role(chan, AST_TRANSFERER_ROLE_NAME) ||
6426  !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "ATTENDEDTRANSFER")) ||
6427  !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "BLINDTRANSFER")))) {
6428  /* Channel that is hanging up is doing it as part of a transfer.
6429  * We'll get a transfer event later
6430  */
6431  ao2_unlock(queue_data);
6432  return;
6433  }
6434 
6435  caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6436  member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6437 
6438  ao2_unlock(queue_data);
6439 
6440  ast_debug(3, "Detected hangup of queue %s channel %s\n", reason == CALLER ? "caller" : "member",
6441  channel_blob->snapshot->base->name);
6442 
6443  ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername,
6444  reason == CALLER ? "COMPLETECALLER" : "COMPLETEAGENT", "%ld|%ld|%d",
6445  (long) (queue_data->starttime - queue_data->holdstart),
6446  (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6447 
6448  send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6449  queue_data->holdstart, queue_data->starttime, reason);
6450  update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6451  queue_data->starttime);
6452  remove_stasis_subscriptions(queue_data);
6453 }
6454 
6455 static void handle_masquerade(void *userdata, struct stasis_subscription *sub,
6456  struct stasis_message *msg)
6457 {
6458  struct queue_stasis_data *queue_data = userdata;
6459  struct ast_channel_blob *channel_blob = stasis_message_data(msg);
6460  const char *new_channel_id;
6461 
6462  new_channel_id = ast_json_string_get(ast_json_object_get(channel_blob->blob, "newchanneluniqueid"));
6463 
6464  ao2_lock(queue_data);
6465 
6466  if (queue_data->dying) {
6467  ao2_unlock(queue_data);
6468  return;
6469  }
6470 
6471  if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->caller_uniqueid)) {
6472  ast_debug(1, "Replacing caller channel %s with %s due to masquerade\n", queue_data->caller_uniqueid, new_channel_id);
6473  ast_string_field_set(queue_data, caller_uniqueid, new_channel_id);
6474  } else if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->member_uniqueid)) {
6475  ast_debug(1, "Replacing member channel %s with %s due to masquerade\n", queue_data->member_uniqueid, new_channel_id);
6476  ast_string_field_set(queue_data, member_uniqueid, new_channel_id);
6477  }
6478 
6479  ao2_unlock(queue_data);
6480 }
6481 
6482 /*!
6483  * \internal
6484  * \brief Callback for all stasis channel events
6485  *
6486  * Based on the event and the channels involved, the work is farmed out into
6487  * subroutines for further processing.
6488  */
6489 static void queue_channel_cb(void *userdata, struct stasis_subscription *sub,
6490  struct stasis_message *msg)
6491 {
6492  if (stasis_subscription_final_message(sub, msg)) {
6493  ao2_cleanup(userdata);
6494  }
6495 }
6496 
6497 /*!
6498  * \internal
6499  * \brief Create stasis subscriptions for a particular call in the queue.
6500  *
6501  * These subscriptions are created once the call has been answered. The subscriptions
6502  * are put in place so that call progress may be tracked. Once the call can be determined
6503  * to have ended, then messages are logged to the queue log and stasis events are emitted.
6504  *
6505  * \param qe The queue entry representing the caller
6506  * \param peer The channel that has answered the call
6507  * \param mem The queue member that answered the call
6508  * \param holdstart The time at which the caller entered the queue
6509  * \param starttime The time at which the call was answered
6510  * \param callcompletedinsl Indicates if the call was answered within the configured service level of the queue.
6511  * \retval 0 Success
6512  * \retval non-zero Failure
6513  */
6514 static int setup_stasis_subs(struct queue_ent *qe, struct ast_channel *peer, struct member *mem,
6515  time_t holdstart, time_t starttime, int callcompletedinsl)
6516 {
6517  struct queue_stasis_data *queue_data = queue_stasis_data_alloc(qe, peer, mem, holdstart, starttime, callcompletedinsl);
6518 
6519  if (!queue_data) {
6520  return -1;
6521  }
6522 
6524  if (!queue_data->bridge_router) {
6525  ao2_ref(queue_data, -1);
6526  return -1;
6527  }
6528 
6530  handle_bridge_enter, queue_data);
6532  handle_blind_transfer, queue_data);
6534  handle_attended_transfer, queue_data);
6536  queue_bridge_cb, queue_data);
6537 
6539  if (!queue_data->channel_router) {
6540  /* Unsubscribing from the bridge router will remove the only ref of queue_data,
6541  * thus beginning the destruction process
6542  */
6544  queue_data->bridge_router = NULL;
6545  return -1;
6546  }
6547 
6548  ao2_ref(queue_data, +1);
6550  handle_local_optimization_begin, queue_data);
6552  handle_local_optimization_end, queue_data);
6554  handle_hangup, queue_data);
6556  handle_masquerade, queue_data);
6558  queue_channel_cb, queue_data);
6559 
6560  return 0;
6561 }
6562 
6564  struct call_queue *q;
6566 };
6567 
6568 static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
6569 {
6570  struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data;
6571  ao2_ref(qeb, +1);
6572  qeb->chan = originator;
6573 }
6574 
6575 static void end_bridge_callback(void *data)
6576 {
6577  struct queue_end_bridge *qeb = data;
6578  struct call_queue *q = qeb->q;
6579  struct ast_channel *chan = qeb->chan;
6580 
6581  if (ao2_ref(qeb, -1) == 1) {
6582  set_queue_variables(q, chan);
6583  /* This unrefs the reference we made in try_calling when we allocated qeb */
6584  queue_t_unref(q, "Expire bridge_config reference");
6585  }
6586 }
6587 
6588 /*!
6589  * \internal
6590  * \brief Setup the after bridge goto location on the peer.
6591  * \since 12.0.0
6592  *
6593  * \param chan Calling channel for bridge.
6594  * \param peer Peer channel for bridge.
6595  * \param opts Dialing option flags.
6596  * \param opt_args Dialing option argument strings.
6597  *
6598  * \return Nothing
6599  */
6600 static void setup_peer_after_bridge_goto(struct ast_channel *chan, struct ast_channel *peer, struct ast_flags *opts, char *opt_args[])
6601 {
6602  const char *context;
6603  const char *extension;
6604  int priority;
6605 
6606  if (ast_test_flag(opts, OPT_CALLEE_GO_ON)) {
6607  ast_channel_lock(chan);
6608  context = ast_strdupa(ast_channel_context(chan));
6609  extension = ast_strdupa(ast_channel_exten(chan));
6610  priority = ast_channel_priority(chan);
6611  ast_channel_unlock(chan);
6612  ast_bridge_set_after_go_on(peer, context, extension, priority,
6613  opt_args[OPT_ARG_CALLEE_GO_ON]);
6614  }
6615 }
6616 
6617 static void escape_and_substitute(struct ast_channel *chan, const char *input,
6618  char *output, size_t size)
6619 {
6620  const char *m = input;
6621  char escaped[size];
6622  char *p;
6623 
6624  for (p = escaped; p < escaped + size - 1; p++, m++) {
6625  switch (*m) {
6626  case '^':
6627  if (*(m + 1) == '{') {
6628  *p = '$';
6629  }
6630  break;
6631  case ',':
6632  *p++ = '\\';
6633  /* Fall through */
6634  default:
6635  *p = *m;
6636  }
6637  if (*m == '\0')
6638  break;
6639  }
6640 
6641  if (p == escaped + size) {
6642  escaped[size - 1] = '\0';
6643  }
6644 
6645  pbx_substitute_variables_helper(chan, escaped, output, size - 1);
6646 }
6647 
6648 static void setup_mixmonitor(struct queue_ent *qe, const char *filename)
6649 {
6650  char escaped_filename[256];
6651  char file_with_ext[sizeof(escaped_filename) + sizeof(qe->parent->monfmt)];
6652  char mixmonargs[1512];
6653  char escaped_monitor_exec[1024];
6654  const char *monitor_options;
6655  const char *monitor_exec;
6656 
6657  escaped_monitor_exec[0] = '\0';
6658 
6659  if (filename) {
6660  escape_and_substitute(qe->chan, filename, escaped_filename, sizeof(escaped_filename));
6661  } else {
6662  ast_copy_string(escaped_filename, ast_channel_uniqueid(qe->chan), sizeof(escaped_filename));
6663  }
6664 
6665  ast_channel_lock(qe->chan);
6666  if ((monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"))) {
6667  monitor_exec = ast_strdupa(monitor_exec);
6668  }
6669  if ((monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"))) {
6670  monitor_options = ast_strdupa(monitor_options);
6671  } else {
6672  monitor_options = "";
6673  }
6674  ast_channel_unlock(qe->chan);
6675 
6676  if (monitor_exec) {
6677  escape_and_substitute(qe->chan, monitor_exec, escaped_monitor_exec, sizeof(escaped_monitor_exec));
6678  }
6679 
6680  snprintf(file_with_ext, sizeof(file_with_ext), "%s.%s", escaped_filename, qe->parent->monfmt);
6681 
6682  if (!ast_strlen_zero(escaped_monitor_exec)) {
6683  snprintf(mixmonargs, sizeof(mixmonargs), "b%s,%s", monitor_options, escaped_monitor_exec);
6684  } else {
6685  snprintf(mixmonargs, sizeof(mixmonargs), "b%s", monitor_options);
6686  }
6687 
6688  ast_debug(1, "Arguments being passed to MixMonitor: %s,%s\n", file_with_ext, mixmonargs);
6689 
6690  if (ast_start_mixmonitor(qe->chan, file_with_ext, mixmonargs)) {
6691  ast_log(LOG_WARNING, "Unable to start mixmonitor. Is the MixMonitor app loaded?\n");
6692  }
6693 }
6694 
6695 /*!
6696  * \internal
6697  * \brief A large function which calls members, updates statistics, and bridges the caller and a member
6698  *
6699  * Here is the process of this function
6700  * 1. Process any options passed to the Queue() application. Options here mean the third argument to Queue()
6701  * 2. Iterate trough the members of the queue, creating a callattempt corresponding to each member.
6702  * 3. Call ring_one to place a call to the appropriate member(s)
6703  * 4. Call wait_for_answer to wait for an answer. If no one answers, return.
6704  * 5. Take care of any holdtime announcements, member delays, or other options which occur after a call has been answered.
6705  * 6. Start the monitor or mixmonitor if the option is set
6706  * 7. Remove the caller from the queue to allow other callers to advance
6707  * 8. Bridge the call.
6708  * 9. Do any post processing after the call has disconnected.
6709  *
6710  * \param[in] qe the queue_ent structure which corresponds to the caller attempting to reach members
6711  * \param[in] opts the options passed as the third parameter to the Queue() application
6712  * \param[in] opt_args the options passed as the third parameter to the Queue() application
6713  * \param[in] announceoverride filename to play to user when waiting
6714  * \param[in] url the url passed as the fourth parameter to the Queue() application
6715  * \param[in,out] tries the number of times we have tried calling queue members
6716  * \param[out] noption set if the call to Queue() has the 'n' option set.
6717  * \param[in] agi the agi passed as the fifth parameter to the Queue() application
6718  * \param[in] macro the macro passed as the sixth parameter to the Queue() application
6719  * \param[in] gosub the gosub passed as the seventh parameter to the Queue() application
6720  * \param[in] ringing 1 if the 'r' option is set, otherwise 0
6721  */
6722 static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_args, char *announceoverride, const char *url, int *tries, int *noption, const char *agi, const char *macro, const char *gosub, int ringing)
6723 {
6724  struct member *cur;
6725  struct callattempt *outgoing = NULL; /* the list of calls we are building */
6726  int to, orig;
6727  char oldexten[AST_MAX_EXTENSION]="";
6728  char oldcontext[AST_MAX_CONTEXT]="";
6729  char queuename[256]="";
6730  struct ast_channel *peer;
6731  struct ast_channel *which;
6732  struct callattempt *lpeer;
6733  struct member *member;
6734  struct ast_app *application;
6735  int res = 0, bridge = 0;
6736  int numbusies = 0;
6737  int x=0;
6738  char *announce = NULL;
6739  char digit = 0;
6740  time_t now = time(NULL);
6741  struct ast_bridge_config bridge_config;
6742  char nondataquality = 1;
6743  char *agiexec = NULL;
6744  char *macroexec = NULL;
6745  char *gosubexec = NULL;
6746  const char *monitorfilename;
6747  char tmpid[256];
6748  int forwardsallowed = 1;
6749  int block_connected_line = 0;
6750  struct ao2_iterator memi;
6752  int callcompletedinsl;
6753  time_t starttime;
6754 
6755  memset(&bridge_config, 0, sizeof(bridge_config));
6756  tmpid[0] = 0;
6757  time(&now);
6758 
6759  /* If we've already exceeded our timeout, then just stop
6760  * This should be extremely rare. queue_exec will take care
6761  * of removing the caller and reporting the timeout as the reason.
6762  */
6763  if (qe->expire && now >= qe->expire) {
6764  res = 0;
6765  goto out;
6766  }
6767 
6768  if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER)) {
6770  }
6771  if (ast_test_flag(&opts, OPT_CALLER_TRANSFER)) {
6773  }
6774  if (ast_test_flag(&opts, OPT_CALLEE_AUTOMON)) {
6776  }
6777  if (ast_test_flag(&opts, OPT_CALLER_AUTOMON)) {
6779  }
6780  if (ast_test_flag(&opts, OPT_DATA_QUALITY)) {
6781  nondataquality = 0;
6782  }
6783  if (ast_test_flag(&opts, OPT_CALLEE_HANGUP)) {
6785  }
6786  if (ast_test_flag(&opts, OPT_CALLER_HANGUP)) {
6788  }
6789  if (ast_test_flag(&opts, OPT_CALLEE_PARK)) {
6791  }
6792  if (ast_test_flag(&opts, OPT_CALLER_PARK)) {
6794  }
6795  if (ast_test_flag(&opts, OPT_NO_RETRY)) {
6798  (*tries)++;
6799  } else {
6800  *tries = ao2_container_count(qe->parent->members);
6801  }
6802  *noption = 1;
6803  }
6804  if (ast_test_flag(&opts, OPT_IGNORE_CALL_FW)) {
6805  forwardsallowed = 0;
6806  }
6808  block_connected_line = 1;
6809  }
6810  if (ast_test_flag(&opts, OPT_CALLEE_AUTOMIXMON)) {
6812  }
6813  if (ast_test_flag(&opts, OPT_CALLER_AUTOMIXMON)) {
6815  }
6816  if (ast_test_flag(&opts, OPT_MARK_AS_ANSWERED)) {
6817  qe->cancel_answered_elsewhere = 1;
6818  }
6819 
6820  /* if the calling channel has AST_CAUSE_ANSWERED_ELSEWHERE set, make sure this is inherited.
6821  (this is mainly to support unreal/local channels)
6822  */
6824  qe->cancel_answered_elsewhere = 1;
6825  }
6826 
6827  ao2_lock(qe->parent);
6828  ast_debug(1, "%s is trying to call a queue member.\n",
6829  ast_channel_name(qe->chan));
6830  ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
6831  if (!ast_strlen_zero(qe->announce)) {
6832  announce = qe->announce;
6833  }
6834  if (!ast_strlen_zero(announceoverride)) {
6835  announce = announceoverride;
6836  }
6837 
6838  memi = ao2_iterator_init(qe->parent->members, 0);
6839  while ((cur = ao2_iterator_next(&memi))) {
6840  struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
6841  if (!tmp) {
6842  ao2_ref(cur, -1);
6843  ao2_iterator_destroy(&memi);
6844  ao2_unlock(qe->parent);
6845  goto out;
6846  }
6847 
6848  /*
6849  * Seed the callattempt's connected line information with previously
6850  * acquired connected line info from the queued channel. The
6851  * previously acquired connected line info could have been set
6852  * through the CONNECTED_LINE dialplan function.
6853  */
6854  ast_channel_lock(qe->chan);
6856  ast_channel_unlock(qe->chan);
6857 
6858  tmp->block_connected_update = block_connected_line;
6859  tmp->stillgoing = 1;
6860  tmp->member = cur; /* Place the reference for cur into callattempt. */
6861  ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
6862  /* Calculate the metric for the appropriate strategy. */
6863  if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
6864  /* Put them in the list of outgoing thingies... We're ready now.
6865  XXX If we're forcibly removed, these outgoing calls won't get
6866  hung up XXX */
6867  tmp->q_next = outgoing;
6868  outgoing = tmp;
6869  } else {
6870  callattempt_free(tmp);
6871  }
6872  }
6873  ao2_iterator_destroy(&memi);
6874 
6876  /* Application arguments have higher timeout priority (behaviour for <=1.6) */
6877  if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout)) {
6878  to = (qe->expire - now) * 1000;
6879  } else {
6880  to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
6881  }
6882  } else {
6883  /* Config timeout is higher priority thatn application timeout */
6884  if (qe->expire && qe->expire<=now) {
6885  to = 0;
6886  } else if (qe->parent->timeout) {
6887  to = qe->parent->timeout * 1000;
6888  } else {
6889  to = -1;
6890  }
6891  }
6892  orig = to;
6893  ++qe->pending;
6894  ao2_unlock(qe->parent);
6895  /* Call the queue members with the best metric now. */
6896  ring_one(qe, outgoing, &numbusies);
6897  lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies,
6899  forwardsallowed);
6900 
6901  ao2_lock(qe->parent);
6903  store_next_rr(qe, outgoing);
6904 
6905  }
6906  if (qe->parent->strategy == QUEUE_STRATEGY_LINEAR) {
6907  store_next_lin(qe, outgoing);
6908  }
6909  ao2_unlock(qe->parent);
6910  peer = lpeer ? lpeer->chan : NULL;
6911  if (!peer) {
6912  qe->pending = 0;
6913  if (to) {
6914  /* Must gotten hung up */
6915  res = -1;
6916  } else {
6917  /* User exited by pressing a digit */
6918  res = digit;
6919  }
6920  if (res == -1) {
6921  ast_debug(1, "%s: Nobody answered.\n", ast_channel_name(qe->chan));
6922  }
6923  } else { /* peer is valid */
6924  RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
6925  RAII_VAR(struct ast_str *, interfacevar, ast_str_create(325), ast_free);
6926  /* Ah ha! Someone answered within the desired timeframe. Of course after this
6927  we will always return with -1 so that it is hung up properly after the
6928  conversation. */
6929  if (!strcmp(ast_channel_tech(qe->chan)->type, "DAHDI")) {
6930  ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
6931  }
6932  if (!strcmp(ast_channel_tech(peer)->type, "DAHDI")) {
6933  ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
6934  }
6935  /* Update parameters for the queue */
6936  time(&now);
6937  recalc_holdtime(qe, (now - qe->start));
6938  member = lpeer->member;
6939  ao2_lock(qe->parent);
6940  callcompletedinsl = member->callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel);
6941  ao2_unlock(qe->parent);
6942  /* Increment the refcount for this member, since we're going to be using it for awhile in here. */
6943  ao2_ref(member, 1);
6944  hangupcalls(qe, outgoing, peer, qe->cancel_answered_elsewhere);
6945  outgoing = NULL;
6946  if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
6947  int res2;
6948 
6949  res2 = ast_autoservice_start(qe->chan);
6950  if (!res2) {
6951  if (qe->parent->memberdelay) {
6952  ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
6953  res2 = ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
6954  }
6955  if (!res2 && announce) {
6956  if (play_file(peer, announce) < 0) {
6957  ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", announce, ast_channel_name(peer));
6958  }
6959  }
6960  if (!res2 && qe->parent->reportholdtime) {
6961  if (!play_file(peer, qe->parent->sound_reporthold)) {
6962  long holdtime, holdtimesecs;
6963 
6964  time(&now);
6965  holdtime = labs((now - qe->start) / 60);
6966  holdtimesecs = labs((now - qe->start) % 60);
6967  if (holdtime > 0) {
6968  ast_say_number(peer, holdtime, AST_DIGIT_ANY, ast_channel_language(peer), NULL);
6969  if (play_file(peer, qe->parent->sound_minutes) < 0) {
6970  ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_minutes, ast_channel_name(peer));
6971  }
6972  }
6973  if (holdtimesecs > 1) {
6974  ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, ast_channel_language(peer), NULL);
6975  if (play_file(peer, qe->parent->sound_seconds) < 0) {
6976  ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_seconds, ast_channel_name(peer));
6977  }
6978  }
6979  }
6980  }
6982  }
6983  if (ast_check_hangup(peer)) {
6984  /* Agent must have hung up */
6985  ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", ast_channel_name(peer));
6986  ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "AGENTDUMP", "%s", "");
6987 
6988  blob = ast_json_pack("{s: s, s: s, s: s}",
6989  "Queue", queuename,
6990  "Interface", member->interface,
6991  "MemberName", member->membername);
6992  queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_dump_type(), blob);
6993 
6996  pending_members_remove(member);
6997  ao2_ref(member, -1);
6998  goto out;
6999  } else if (ast_check_hangup(qe->chan)) {
7000  /* Caller must have hung up just before being connected */
7001  ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", ast_channel_name(peer));
7002  ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) (time(NULL) - qe->start));
7003  record_abandoned(qe);
7004  qe->handled = -1;
7007  pending_members_remove(member);
7008  ao2_ref(member, -1);
7009  return -1;
7010  }
7011  }
7012  /* Stop music on hold */
7013  if (ringing) {
7014  ast_indicate(qe->chan,-1);
7015  } else {
7016  ast_moh_stop(qe->chan);
7017  }
7018 
7019  /* Make sure channels are compatible */
7020  res = ast_channel_make_compatible(qe->chan, peer);
7021  if (res < 0) {
7022  ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "SYSCOMPAT", "%s", "");
7023  ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", ast_channel_name(qe->chan), ast_channel_name(peer));
7024  record_abandoned(qe);
7027  pending_members_remove(member);
7028  ao2_ref(member, -1);
7029  return -1;
7030  }
7031 
7032  /* Play announcement to the caller telling it's his turn if defined */
7034  if (play_file(qe->chan, qe->parent->sound_callerannounce)) {
7035  ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", qe->parent->sound_callerannounce);
7036  }
7037  }
7038 
7039  ao2_lock(qe->parent);
7040  /* if setinterfacevar is defined, make member variables available to the channel */
7041  /* use pbx_builtin_setvar to set a load of variables with one call */
7042  if (qe->parent->setinterfacevar && interfacevar) {
7043  ast_str_set(&interfacevar, 0, "MEMBERINTERFACE=%s,MEMBERNAME=%s,MEMBERCALLS=%d,MEMBERLASTCALL=%ld,MEMBERPENALTY=%d,MEMBERDYNAMIC=%d,MEMBERREALTIME=%d",
7044  member->interface, member->membername, member->calls, (long)member->lastcall, member->penalty, member->dynamic, member->realtime);
7045  pbx_builtin_setvar_multiple(qe->chan, ast_str_buffer(interfacevar));
7046  pbx_builtin_setvar_multiple(peer, ast_str_buffer(interfacevar));
7047  }
7048 
7049  /* if setqueueentryvar is defined, make queue entry (i.e. the caller) variables available to the channel */
7050  /* use pbx_builtin_setvar to set a load of variables with one call */
7051  if (qe->parent->setqueueentryvar && interfacevar) {
7052  ast_str_set(&interfacevar, 0, "QEHOLDTIME=%ld,QEORIGINALPOS=%d",
7053  (long) (time(NULL) - qe->start), qe->opos);
7054  pbx_builtin_setvar_multiple(qe->chan, ast_str_buffer(interfacevar));
7055  pbx_builtin_setvar_multiple(peer, ast_str_buffer(interfacevar));
7056  }
7057 
7058  ao2_unlock(qe->parent);
7059 
7060  /* try to set queue variables if configured to do so*/
7061  set_queue_variables(qe->parent, qe->chan);
7062  set_queue_variables(qe->parent, peer);
7063 
7064  setup_peer_after_bridge_goto(qe->chan, peer, &opts, opt_args);
7065  ast_channel_lock(qe->chan);
7066  if ((monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"))) {
7067  monitorfilename = ast_strdupa(monitorfilename);
7068  }
7069  ast_channel_unlock(qe->chan);
7070 
7071  /* Begin Monitoring */
7072  if (*qe->parent->monfmt) {
7073  if (!qe->parent->montype) {
7074  const char *monexec;
7075  ast_debug(1, "Starting Monitor as requested.\n");
7076  ast_channel_lock(qe->chan);
7077  if ((monexec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC")) || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS")) {
7078  which = qe->chan;
7079  monexec = monexec ? ast_strdupa(monexec) : NULL;
7080  } else {
7081  which = peer;
7082  }
7083  ast_channel_unlock(qe->chan);
7084  if (monitorfilename) {
7085  ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1, X_REC_IN | X_REC_OUT, NULL);
7086  } else if (qe->chan) {
7088  } else {
7089  /* Last ditch effort -- no channel, make up something */
7090  snprintf(tmpid, sizeof(tmpid), "chan-%lx", (unsigned long)ast_random());
7091  ast_monitor_start(which, qe->parent->monfmt, tmpid, 1, X_REC_IN | X_REC_OUT, NULL);
7092  }
7093  if (!ast_strlen_zero(monexec)) {
7094  ast_monitor_setjoinfiles(which, 1);
7095  }
7096  } else {
7097  setup_mixmonitor(qe, monitorfilename);
7098  }
7099  }
7100  /* Drop out of the queue at this point, to prepare for next caller */
7101  leave_queue(qe);
7102  if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
7103  ast_debug(1, "app_queue: sendurl=%s.\n", url);
7104  ast_channel_sendurl(peer, url);
7105  }
7106 
7107  /* run a macro for this connection if defined. The macro simply returns, no action is taken on the result */
7108  /* use macro from dialplan if passed as a option, otherwise use the default queue macro */
7109  if (!ast_strlen_zero(macro)) {
7110  macroexec = ast_strdupa(macro);
7111  } else {
7112  if (qe->parent->membermacro) {
7113  macroexec = ast_strdupa(qe->parent->membermacro);
7114  }
7115  }
7116 
7117  if (!ast_strlen_zero(macroexec)) {
7118  ast_debug(1, "app_queue: macro=%s.\n", macroexec);
7119  ast_app_exec_macro(qe->chan, peer, macroexec);
7120  }
7121 
7122  /* run a gosub for this connection if defined. The gosub simply returns, no action is taken on the result */
7123  /* use gosub from dialplan if passed as a option, otherwise use the default queue gosub */
7124  if (!ast_strlen_zero(gosub)) {
7125  gosubexec = ast_strdupa(gosub);
7126  } else {
7127  if (qe->parent->membergosub) {
7128  gosubexec = ast_strdupa(qe->parent->membergosub);
7129  }
7130  }
7131 
7132  if (!ast_strlen_zero(gosubexec)) {
7133  char *gosub_args = NULL;
7134  char *gosub_argstart;
7135 
7136  ast_debug(1, "app_queue: gosub=%s.\n", gosubexec);
7137 
7138  gosub_argstart = strchr(gosubexec, ',');
7139  if (gosub_argstart) {
7140  const char *what_is_s = "s";
7141  *gosub_argstart = 0;
7142  if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL)) &&
7143  ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL))) {
7144  what_is_s = "~~s~~";
7145  }
7146  if (ast_asprintf(&gosub_args, "%s,%s,1(%s)", gosubexec, what_is_s, gosub_argstart + 1) < 0) {
7147  gosub_args = NULL;
7148  }
7149  *gosub_argstart = ',';
7150  } else {
7151  const char *what_is_s = "s";
7152  if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL)) &&
7153  ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL))) {
7154  what_is_s = "~~s~~";
7155  }
7156  if (ast_asprintf(&gosub_args, "%s,%s,1", gosubexec, what_is_s) < 0) {
7157  gosub_args = NULL;
7158  }
7159  }
7160  if (gosub_args) {
7161  ast_app_exec_sub(qe->chan, peer, gosub_args, 0);
7162  ast_free(gosub_args);
7163  } else {
7164  ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n");
7165  }
7166  }
7167 
7168  if (!ast_strlen_zero(agi)) {
7169  ast_debug(1, "app_queue: agi=%s.\n", agi);
7170  application = pbx_findapp("agi");
7171  if (application) {
7172  agiexec = ast_strdupa(agi);
7173  pbx_exec(qe->chan, application, agiexec);
7174  } else {
7175  ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
7176  }
7177  }
7178  qe->handled++;
7179 
7180  ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "CONNECT", "%ld|%s|%ld", (long) (time(NULL) - qe->start), ast_channel_uniqueid(peer),
7181  (long)(orig - to > 0 ? (orig - to) / 1000 : 0));
7182 
7183  blob = ast_json_pack("{s: s, s: s, s: s, s: I, s: I}",
7184  "Queue", queuename,
7185  "Interface", member->interface,
7186  "MemberName", member->membername,
7187  "HoldTime", (ast_json_int_t)(time(NULL) - qe->start),
7188  "RingTime", (ast_json_int_t)(orig - to > 0 ? (orig - to) / 1000 : 0));
7189  queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_connect_type(), blob);
7190 
7191  ast_copy_string(oldcontext, ast_channel_context(qe->chan), sizeof(oldcontext));
7192  ast_copy_string(oldexten, ast_channel_exten(qe->chan), sizeof(oldexten));
7193 
7194  if ((queue_end_bridge = ao2_alloc(sizeof(*queue_end_bridge), NULL))) {
7195  queue_end_bridge->q = qe->parent;
7196  queue_end_bridge->chan = qe->chan;
7197  bridge_config.end_bridge_callback = end_bridge_callback;
7198  bridge_config.end_bridge_callback_data = queue_end_bridge;
7200  /* Since queue_end_bridge can survive beyond the life of this call to Queue, we need
7201  * to make sure to increase the refcount of this queue so it cannot be freed until we
7202  * are done with it. We remove this reference in end_bridge_callback.
7203  */
7204  queue_t_ref(qe->parent, "For bridge_config reference");
7205  }
7206 
7207  ao2_lock(qe->parent);
7208  time(&member->starttime);
7209  starttime = member->starttime;
7210  ao2_unlock(qe->parent);
7211  /* As a queue member may end up in multiple calls at once if a transfer occurs with
7212  * a Local channel in the mix we pass the current call information (starttime) to the
7213  * Stasis subscriptions so when they update the queue member data it becomes a noop
7214  * if this call is no longer between the caller and the queue member.
7215  */
7216  setup_stasis_subs(qe, peer, member, qe->start, starttime, callcompletedinsl);
7217  bridge = ast_bridge_call_with_flags(qe->chan, peer, &bridge_config,
7219 
7220  res = bridge ? bridge : 1;
7221  ao2_ref(member, -1);
7222  }
7223 out:
7224  hangupcalls(qe, outgoing, NULL, qe->cancel_answered_elsewhere);
7225 
7226  return res;
7227 }
7228 
7229 static int wait_a_bit(struct queue_ent *qe)
7230 {
7231  /* Don't need to hold the lock while we setup the outgoing calls */
7232  int retrywait = qe->parent->retry * 1000;
7233 
7234  int res = ast_waitfordigit(qe->chan, retrywait);
7235  if (res > 0 && !valid_exit(qe, res)) {
7236  res = 0;
7237  }
7238 
7239  return res;
7240 }
7241 
7242 static struct member *interface_exists(struct call_queue *q, const char *interface)
7243 {
7244  struct member *mem;
7245  struct ao2_iterator mem_iter;
7246 
7247  if (!q) {
7248  return NULL;
7249  }
7250  mem_iter = ao2_iterator_init(q->members, 0);
7251  while ((mem = ao2_iterator_next(&mem_iter))) {
7252  if (!strcasecmp(interface, mem->interface)) {
7253  ao2_iterator_destroy(&mem_iter);
7254  return mem;
7255  }
7256  ao2_ref(mem, -1);
7257  }
7258  ao2_iterator_destroy(&mem_iter);
7259 
7260  return NULL;
7261 }
7262 
7263 
7264 /*! \brief Dump all members in a specific queue to the database
7265  * \code
7266  * <pm_family>/<queuename> = <interface>;<penalty>;<paused>;<state_interface>[|...]
7267  * \endcode
7268  */
7269 static void dump_queue_members(struct call_queue *pm_queue)
7270 {
7271  struct member *cur_member;
7272  struct ast_str *value;
7273  struct ao2_iterator mem_iter;
7274 
7275  if (!pm_queue) {
7276  return;
7277  }
7278 
7279  /* 4K is a reasonable default for most applications, but we grow to
7280  * accommodate more if necessary. */
7281  if (!(value = ast_str_create(4096))) {
7282  return;
7283  }
7284 
7285  mem_iter = ao2_iterator_init(pm_queue->members, 0);
7286  while ((cur_member = ao2_iterator_next(&mem_iter))) {
7287  if (!cur_member->dynamic) {
7288  ao2_ref(cur_member, -1);
7289  continue;
7290  }
7291 
7292  ast_str_append(&value, 0, "%s%s;%d;%d;%s;%s;%s;%d",
7293  ast_str_strlen(value) ? "|" : "",
7294  cur_member->interface,
7295  cur_member->penalty,
7296  cur_member->paused,
7297  cur_member->membername,
7298  cur_member->state_interface,
7299  cur_member->reason_paused,
7300  cur_member->wrapuptime);
7301 
7302  ao2_ref(cur_member, -1);
7303  }
7304  ao2_iterator_destroy(&mem_iter);
7305 
7306  if (ast_str_strlen(value) && !cur_member) {
7307  if (ast_db_put(pm_family, pm_queue->name, ast_str_buffer(value))) {
7308  ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
7309  }
7310  } else {
7311  /* Delete the entry if the queue is empty or there is an error */
7312  ast_db_del(pm_family, pm_queue->name);
7313  }
7314 
7315  ast_free(value);
7316 }
7317 
7318 /*! \brief Remove member from queue
7319  * \retval RES_NOT_DYNAMIC when they aren't a RT member
7320  * \retval RES_NOSUCHQUEUE queue does not exist
7321  * \retval RES_OKAY removed member from queue
7322  * \retval RES_EXISTS queue exists but no members
7323 */
7324 static int remove_from_queue(const char *queuename, const char *interface)
7325 {
7326  struct call_queue *q, tmpq = {
7327  .name = queuename,
7328  };
7329  struct member *mem, tmpmem;
7330  int res = RES_NOSUCHQUEUE;
7331 
7332  ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
7333  if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Temporary reference for interface removal"))) {
7334  ao2_lock(q);
7335  if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
7336  /* XXX future changes should beware of this assumption!! */
7337  /*Change Penalty on realtime users*/
7338  if (mem->realtime && !ast_strlen_zero(mem->rt_uniqueid) && negative_penalty_invalid) {
7339  update_realtime_member_field(mem, q->name, "penalty", "-1");
7340  } else if (!mem->dynamic) {
7341  ao2_ref(mem, -1);
7342  ao2_unlock(q);
7343  queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference");
7344  return RES_NOT_DYNAMIC;
7345  }
7346  queue_publish_member_blob(queue_member_removed_type(), queue_member_blob_create(q, mem));
7347 
7348  member_remove_from_queue(q, mem);
7349  ao2_ref(mem, -1);
7350 
7351  if (queue_persistent_members) {
7352  dump_queue_members(q);
7353  }
7354 
7355  if (!num_available_members(q)) {
7357  }
7358 
7359  res = RES_OKAY;
7360  } else {
7361  res = RES_EXISTS;
7362  }
7363  ao2_unlock(q);
7364  queue_t_unref(q, "Expiring temporary reference");
7365  }
7366 
7367  return res;
7368 }
7369 
7370 /*! \brief Add member to queue
7371  * \retval RES_NOT_DYNAMIC when they aren't a RT member
7372  * \retval RES_NOSUCHQUEUE queue does not exist
7373  * \retval RES_OKAY added member from queue
7374  * \retval RES_EXISTS queue exists but no members
7375  * \retval RES_OUT_OF_MEMORY queue exists but not enough memory to create member
7376 */
7377 static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface, const char *reason_paused, int wrapuptime)
7378 {
7379  struct call_queue *q;
7380  struct member *new_member, *old_member;
7381  int res = RES_NOSUCHQUEUE;
7382 
7383  /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7384  * short-circuits if the queue is already in memory. */
7385  if (!(q = find_load_queue_rt_friendly(queuename))) {
7386  return res;
7387  }
7388 
7389  ao2_lock(q);
7390  if ((old_member = interface_exists(q, interface)) == NULL) {
7391  if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface, q->ringinuse, wrapuptime))) {
7392  new_member->dynamic = 1;
7393  if (reason_paused) {
7394  ast_copy_string(new_member->reason_paused, reason_paused, sizeof(new_member->reason_paused));
7395  }
7396  member_add_to_queue(q, new_member);
7397  queue_publish_member_blob(queue_member_added_type(), queue_member_blob_create(q, new_member));
7398 
7399  if (is_member_available(q, new_member)) {
7401  }
7402 
7403  ao2_ref(new_member, -1);
7404  new_member = NULL;
7405 
7406  if (dump) {
7407  dump_queue_members(q);
7408  }
7409 
7410  res = RES_OKAY;
7411  } else {
7412  res = RES_OUTOFMEMORY;
7413  }
7414  } else {
7415  ao2_ref(old_member, -1);
7416  res = RES_EXISTS;
7417  }
7418  ao2_unlock(q);
7419  queue_t_unref(q, "Expiring temporary reference");
7420 
7421  return res;
7422 }
7423 
7424 
7425 /*! \brief Change priority caller into a queue
7426  * \retval RES_NOSUCHQUEUE queue does not exist
7427  * \retval RES_OKAY change priority
7428  * \retval RES_NOT_CALLER queue exists but no caller
7429 */
7430 static int change_priority_caller_on_queue(const char *queuename, const char *caller, int priority)
7431 {
7432  struct call_queue *q;
7433  struct queue_ent *qe;
7434  int res = RES_NOSUCHQUEUE;
7435 
7436  /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7437  * short-circuits if the queue is already in memory. */
7438  if (!(q = find_load_queue_rt_friendly(queuename))) {
7439  return res;
7440  }
7441 
7442  ao2_lock(q);
7443  res = RES_NOT_CALLER;
7444  for (qe = q->head; qe; qe = qe->next) {
7445  if (strcmp(ast_channel_name(qe->chan), caller) == 0) {
7446  ast_debug(1, "%s Caller new prioriry %d in queue %s\n",
7447  caller, priority, queuename);
7448  qe->prio = priority;
7449  res = RES_OKAY;
7450  }
7451  }
7452  ao2_unlock(q);
7453  return res;
7454 }
7455 
7456 
7457 static int publish_queue_member_pause(struct call_queue *q, struct member *member)
7458 {
7459  struct ast_json *json_blob = queue_member_blob_create(q, member);
7460 
7461  if (!json_blob) {
7462  return -1;
7463  }
7464 
7465  queue_publish_member_blob(queue_member_pause_type(), json_blob);
7466 
7467  return 0;
7468 }
7469 
7470 /*!
7471  * \internal
7472  * \brief Set the pause status of the specific queue member.
7473  *
7474  * \param q Which queue the member belongs.
7475  * \param mem Queue member being paused/unpaused.
7476  * \param reason Why is this happening (Can be NULL/empty for no reason given.)
7477  * \param paused Set to 1 if the member is being paused or 0 to unpause.
7478  *
7479  * \pre The q is locked on entry.
7480  *
7481  * \return Nothing
7482  */
7483 static void set_queue_member_pause(struct call_queue *q, struct member *mem, const char *reason, int paused)
7484 {
7485  if (mem->paused == paused) {
7486  ast_debug(1, "%spausing already-%spaused queue member %s:%s\n",
7487  (paused ? "" : "un"), (paused ? "" : "un"), q->name, mem->interface);
7488  }
7489 
7490  if (mem->realtime) {
7491  if (update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0")) {
7492  ast_log(LOG_WARNING, "Failed %spause update of realtime queue member %s:%s\n",
7493  (paused ? "" : "un"), q->name, mem->interface);
7494  }
7495  }
7496 
7497  mem->paused = paused;
7498  if (paused) {
7499  time(&mem->lastpause); /* update last pause field */
7500  }
7501  if (paused && !ast_strlen_zero(reason)) {
7502  ast_copy_string(mem->reason_paused, reason, sizeof(mem->reason_paused));
7503  } else {
7504  mem->reason_paused[0] = '\0';
7505  }
7506 
7508  AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", q->name, mem->interface);
7509 
7510  if (queue_persistent_members) {
7511  dump_queue_members(q);
7512  }
7513 
7514  if (is_member_available(q, mem)) {
7516  "Queue:%s_avail", q->name);
7517  } else if (!num_available_members(q)) {
7519  "Queue:%s_avail", q->name);
7520  }
7521 
7522  ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"),
7523  "%s", S_OR(reason, ""));
7524 
7526 }
7527 
7528 static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
7529 {
7530  int found = 0;
7531  struct call_queue *q;
7532  struct ao2_iterator queue_iter;
7533 
7534  queue_iter = ao2_iterator_init(queues, 0);
7535  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate over queues"))) {
7536  ao2_lock(q);
7537  if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
7538  struct member *mem;
7539 
7540  if ((mem = interface_exists(q, interface))) {
7541  /*
7542  * Before we do the PAUSE/UNPAUSE, log if this was a
7543  * PAUSEALL/UNPAUSEALL but only on the first found entry.
7544  */
7545  ++found;
7546  if (found == 1
7547  && ast_strlen_zero(queuename)) {
7548  /*
7549  * XXX In all other cases, we use the queue name,
7550  * but since this affects all queues, we cannot.
7551  */
7552  ast_queue_log("NONE", "NONE", mem->membername,
7553  (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", S_OR(reason, ""));
7554  }
7555 
7556  set_queue_member_pause(q, mem, reason, paused);
7557  ao2_ref(mem, -1);
7558  }
7559 
7560  if (!ast_strlen_zero(queuename)) {
7561  ao2_unlock(q);
7562  queue_t_unref(q, "Done with iterator");
7563  break;
7564  }
7565  }
7566 
7567  ao2_unlock(q);
7568  queue_t_unref(q, "Done with iterator");
7569  }
7570  ao2_iterator_destroy(&queue_iter);
7571 
7572  return found ? RESULT_SUCCESS : RESULT_FAILURE;
7573 }
7574 
7575 /*!
7576  * \internal
7577  * \brief helper function for set_member_penalty - given a queue, sets all member penalties with the interface
7578  * \param[in] q queue which is having its member's penalty changed - must be unlocked prior to calling
7579  * \param[in] interface String of interface used to search for queue members being changed
7580  * \param[in] penalty Value penalty is being changed to for the member.
7581  * \retval 0 if the there is no member with interface belonging to q and no change is made
7582  * \retval 1 if the there is a member with interface belonging to q and changes are made
7583  */
7584 static int set_member_penalty_help_members(struct call_queue *q, const char *interface, int penalty)
7585 {
7586  struct member *mem;
7587  int foundinterface = 0;
7588 
7589  ao2_lock(q);
7590  if ((mem = interface_exists(q, interface))) {
7591  foundinterface++;
7592  if (mem->realtime) {
7593  char rtpenalty[80];
7594 
7595  sprintf(rtpenalty, "%i", penalty);
7596  update_realtime_member_field(mem, q->name, "penalty", rtpenalty);
7597  }
7598 
7599  mem->penalty = penalty;
7600 
7601  ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty);
7602  queue_publish_member_blob(queue_member_penalty_type(), queue_member_blob_create(q, mem));
7603  ao2_ref(mem, -1);
7604  }
7605  ao2_unlock(q);
7606 
7607  return foundinterface;
7608 }
7609 
7610 /*!
7611  * \internal
7612  * \brief Set the ringinuse value of the specific queue member.
7613  *
7614  * \param q Which queue the member belongs.
7615  * \param mem Queue member being set.
7616  * \param ringinuse Set to 1 if the member is called when inuse.
7617  *
7618  * \pre The q is locked on entry.
7619  *
7620  * \return Nothing
7621  */
7622 static void set_queue_member_ringinuse(struct call_queue *q, struct member *mem, int ringinuse)
7623 {
7624  if (mem->realtime) {
7625  update_realtime_member_field(mem, q->name, realtime_ringinuse_field,
7626  ringinuse ? "1" : "0");
7627  }
7628 
7629  mem->ringinuse = ringinuse;
7630 
7631  ast_queue_log(q->name, "NONE", mem->interface, "RINGINUSE", "%d", ringinuse);
7632  queue_publish_member_blob(queue_member_ringinuse_type(), queue_member_blob_create(q, mem));
7633 }
7634 
7635 static int set_member_ringinuse_help_members(struct call_queue *q, const char *interface, int ringinuse)
7636 {
7637  struct member *mem;
7638  int foundinterface = 0;
7639 
7640  ao2_lock(q);
7641  if ((mem = interface_exists(q, interface))) {
7642  foundinterface++;
7643  set_queue_member_ringinuse(q, mem, ringinuse);
7644  ao2_ref(mem, -1);
7645  }
7646  ao2_unlock(q);
7647 
7648  return foundinterface;
7649 }
7650 
7651 static int set_member_value_help_members(struct call_queue *q, const char *interface, int property, int value)
7652 {
7653  switch(property) {
7654  case MEMBER_PENALTY:
7655  return set_member_penalty_help_members(q, interface, value);
7656 
7657  case MEMBER_RINGINUSE:
7658  return set_member_ringinuse_help_members(q, interface, value);
7659 
7660  default:
7661  ast_log(LOG_ERROR, "Attempted to set invalid property\n");
7662  return 0;
7663  }
7664 }
7665 
7666 /*!
7667  * \internal
7668  * \brief Sets members penalty, if queuename=NULL we set member penalty in all the queues.
7669  * \param[in] queuename If specified, only act on a member if it belongs to this queue
7670  * \param[in] interface Interface of queue member(s) having priority set.
7671  * \param[in] property Which queue property is being set
7672  * \param[in] penalty Value penalty is being changed to for each member
7673  */
7674 static int set_member_value(const char *queuename, const char *interface, int property, int value)
7675 {
7676  int foundinterface = 0, foundqueue = 0;
7677  struct call_queue *q;
7678  struct ast_config *queue_config = NULL;
7679  struct ao2_iterator queue_iter;
7680 
7681  /* property dependent restrictions on values should be checked in this switch */
7682  switch (property) {
7683  case MEMBER_PENALTY:
7684  if (value < 0 && !negative_penalty_invalid) {
7685  ast_log(LOG_ERROR, "Invalid penalty (%d)\n", value);
7686  return RESULT_FAILURE;
7687  }
7688  }
7689 
7690  if (ast_strlen_zero(queuename)) { /* This means we need to iterate through all the queues. */
7691  if (ast_check_realtime("queues")) {
7692  queue_config = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
7693  if (queue_config) {
7694  char *category = NULL;
7695  while ((category = ast_category_browse(queue_config, category))) {
7696  const char *name = ast_variable_retrieve(queue_config, category, "name");
7697  if (ast_strlen_zero(name)) {
7698  ast_log(LOG_WARNING, "Ignoring realtime queue with a NULL or empty 'name.'\n");
7699  continue;
7700  }
7701  if ((q = find_load_queue_rt_friendly(name))) {
7702  foundqueue++;
7703  foundinterface += set_member_value_help_members(q, interface, property, value);
7704  queue_unref(q);
7705  }
7706  }
7707  }
7708  }
7709 
7710  /* After hitting realtime queues, go back and get the regular ones. */
7711  queue_iter = ao2_iterator_init(queues, 0);
7712  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
7713  foundqueue++;
7714  foundinterface += set_member_value_help_members(q, interface, property, value);
7715  queue_unref(q);
7716  }
7717  ao2_iterator_destroy(&queue_iter);
7718  } else { /* We actually have a queuename, so we can just act on the single queue. */
7719  if ((q = find_load_queue_rt_friendly(queuename))) {
7720  foundqueue++;
7721  foundinterface += set_member_value_help_members(q, interface, property, value);
7722  queue_unref(q);
7723  }
7724  }
7725 
7726  if (foundinterface) {
7727  return RESULT_SUCCESS;
7728  } else if (!foundqueue) {
7729  ast_log (LOG_ERROR, "Invalid queuename\n");
7730  } else {
7731  ast_log (LOG_ERROR, "Invalid interface\n");
7732  }
7733 
7734  return RESULT_FAILURE;
7735 }
7736 
7737 /* \brief Gets members penalty.
7738  * \return Return the members penalty or RESULT_FAILURE on error.
7739 */
7740 static int get_member_penalty(char *queuename, char *interface)
7741 {
7742  int foundqueue = 0, penalty;
7743  struct call_queue *q;
7744  struct member *mem;
7745 
7746  if ((q = find_load_queue_rt_friendly(queuename))) {
7747  foundqueue = 1;
7748  ao2_lock(q);
7749  if ((mem = interface_exists(q, interface))) {
7750  penalty = mem->penalty;
7751  ao2_ref(mem, -1);
7752  ao2_unlock(q);
7753  queue_t_unref(q, "Search complete");
7754  return penalty;
7755  }
7756  ao2_unlock(q);
7757  queue_t_unref(q, "Search complete");
7758  }
7759 
7760  /* some useful debuging */
7761  if (foundqueue) {
7762  ast_log (LOG_ERROR, "Invalid queuename\n");
7763  } else {
7764  ast_log (LOG_ERROR, "Invalid interface\n");
7765  }
7766 
7767  return RESULT_FAILURE;
7768 }
7769 
7770 /*! \brief Reload dynamic queue members persisted into the astdb */
7771 static void reload_queue_members(void)
7772 {
7773  char *cur_ptr;
7774  const char *queue_name;
7775  char *member;
7776  char *interface;
7777  char *membername = NULL;
7778  char *state_interface;
7779  char *penalty_tok;
7780  int penalty = 0;
7781  char *paused_tok;
7782  int paused = 0;
7783  char *wrapuptime_tok;
7784  int wrapuptime = 0;
7785  char *reason_paused;
7786  struct ast_db_entry *db_tree;
7787  struct ast_db_entry *entry;
7788  struct call_queue *cur_queue;
7789  char *queue_data;
7790 
7791  /* Each key in 'pm_family' is the name of a queue */
7792  db_tree = ast_db_gettree(pm_family, NULL);
7793  for (entry = db_tree; entry; entry = entry->next) {
7794 
7795  queue_name = entry->key + strlen(pm_family) + 2;
7796 
7797  {
7798  struct call_queue tmpq = {
7799  .name = queue_name,
7800  };
7801  cur_queue = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Reload queue members");
7802  }
7803 
7804  if (!cur_queue) {
7805  cur_queue = find_load_queue_rt_friendly(queue_name);
7806  }
7807 
7808  if (!cur_queue) {
7809  /* If the queue no longer exists, remove it from the
7810  * database */
7811  ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
7812  ast_db_del(pm_family, queue_name);
7813  continue;
7814  }
7815 
7816  if (ast_db_get_allocated(pm_family, queue_name, &queue_data)) {
7817  queue_t_unref(cur_queue, "Expire reload reference");
7818  continue;
7819  }
7820 
7821  cur_ptr = queue_data;
7822  while ((member = strsep(&cur_ptr, ",|"))) {
7823  if (ast_strlen_zero(member)) {
7824  continue;
7825  }
7826 
7827  interface = strsep(&member, ";");
7828  penalty_tok = strsep(&member, ";");
7829  paused_tok = strsep(&member, ";");
7830  membername = strsep(&member, ";");
7831  state_interface = strsep(&member, ";");
7832  reason_paused = strsep(&member, ";");
7833  wrapuptime_tok = strsep(&member, ";");
7834 
7835  if (!penalty_tok) {
7836  ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
7837  break;
7838  }
7839  penalty = strtol(penalty_tok, NULL, 10);
7840  if (errno == ERANGE) {
7841  ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
7842  break;
7843  }
7844 
7845  if (!paused_tok) {
7846  ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
7847  break;
7848  }
7849  paused = strtol(paused_tok, NULL, 10);
7850  if ((errno == ERANGE) || paused < 0 || paused > 1) {
7851  ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
7852  break;
7853  }
7854 
7855  if (!ast_strlen_zero(wrapuptime_tok)) {
7856  wrapuptime = strtol(wrapuptime_tok, NULL, 10);
7857  if (errno == ERANGE) {
7858  ast_log(LOG_WARNING, "Error converting wrapuptime: %s: Out of range.\n", wrapuptime_tok);
7859  break;
7860  }
7861  }
7862 
7863  ast_debug(1, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d ReasonPause: %s Wrapuptime: %d\n",
7864  queue_name, interface, membername, penalty, paused, reason_paused, wrapuptime);
7865 
7866  if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface, reason_paused, wrapuptime) == RES_OUTOFMEMORY) {
7867  ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
7868  break;
7869  }
7870  }
7871  queue_t_unref(cur_queue, "Expire reload reference");
7872  ast_free(queue_data);
7873  }
7874 
7875  if (db_tree) {
7876  ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
7877  ast_db_freetree(db_tree);
7878  }
7879 }
7880 
7881 /*! \brief PauseQueueMember application */
7882 static int pqm_exec(struct ast_channel *chan, const char *data)
7883 {
7884  char *parse;
7886  AST_APP_ARG(queuename);
7887  AST_APP_ARG(interface);
7889  AST_APP_ARG(reason);
7890  );
7891 
7892  if (ast_strlen_zero(data)) {
7893  ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n");
7894  return -1;
7895  }
7896 
7897  parse = ast_strdupa(data);
7898 
7899  AST_STANDARD_APP_ARGS(args, parse);
7900 
7901  if (ast_strlen_zero(args.interface)) {
7902  ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
7903  return -1;
7904  }
7905 
7906  if (set_member_paused(args.queuename, args.interface, args.reason, 1)) {
7907  ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
7908  pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
7909  return 0;
7910  }
7911 
7912  pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
7913 
7914  return 0;
7915 }
7916 
7917 /*! \brief UnPauseQueueMember application */
7918 static int upqm_exec(struct ast_channel *chan, const char *data)
7919 {
7920  char *parse;
7922  AST_APP_ARG(queuename);
7923  AST_APP_ARG(interface);
7925  AST_APP_ARG(reason);
7926  );
7927 
7928  if (ast_strlen_zero(data)) {
7929  ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename],interface[,options[,reason]])\n");
7930  return -1;
7931  }
7932 
7933  parse = ast_strdupa(data);
7934 
7935  AST_STANDARD_APP_ARGS(args, parse);
7936 
7937  if (ast_strlen_zero(args.interface)) {
7938  ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
7939  return -1;
7940  }
7941 
7942  if (set_member_paused(args.queuename, args.interface, args.reason, 0)) {
7943  ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
7944  pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
7945  return 0;
7946  }
7947 
7948  pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
7949 
7950  return 0;
7951 }
7952 
7953 /*! \brief RemoveQueueMember application */
7954 static int rqm_exec(struct ast_channel *chan, const char *data)
7955 {
7956  int res=-1;
7957  char *parse, *temppos = NULL;
7958  struct member *mem = NULL;
7959 
7961  AST_APP_ARG(queuename);
7963  );
7964 
7965 
7966  if (ast_strlen_zero(data)) {
7967  ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface])\n");
7968  return -1;
7969  }
7970 
7971  parse = ast_strdupa(data);
7972 
7973  AST_STANDARD_APP_ARGS(args, parse);
7974 
7975  if (ast_strlen_zero(args.interface)) {
7976  args.interface = ast_strdupa(ast_channel_name(chan));
7977  temppos = strrchr(args.interface, '-');
7978  if (temppos) {
7979  *temppos = '\0';
7980  }
7981  }
7982 
7983  ast_debug(1, "queue: %s, member: %s\n", args.queuename, args.interface);
7984 
7985  if (log_membername_as_agent) {
7986  mem = find_member_by_queuename_and_interface(args.queuename, args.interface);
7987  }
7988 
7989  switch (remove_from_queue(args.queuename, args.interface)) {
7990  case RES_OKAY:
7991  if (!mem || ast_strlen_zero(mem->membername)) {
7992  ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "REMOVEMEMBER", "%s", "");
7993  } else {
7994  ast_queue_log(args.queuename, ast_channel_uniqueid(chan), mem->membername, "REMOVEMEMBER", "%s", "");
7995  }
7996  ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
7997  pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
7998  res = 0;
7999  break;
8000  case RES_EXISTS:
8001  ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
8002  pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
8003  res = 0;
8004  break;
8005  case RES_NOSUCHQUEUE:
8006  ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
8007  pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
8008  res = 0;
8009  break;
8010  case RES_NOT_DYNAMIC:
8011  ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface);
8012  pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC");
8013  res = 0;
8014  break;
8015  }
8016 
8017  if (mem) {
8018  ao2_ref(mem, -1);
8019  }
8020 
8021  return res;
8022 }
8023 
8024 /*! \brief AddQueueMember application */
8025 static int aqm_exec(struct ast_channel *chan, const char *data)
8026 {
8027  int res=-1;
8028  char *parse, *tmp, *temppos = NULL;
8030  AST_APP_ARG(queuename);
8037  );
8038  int penalty = 0;
8039  int wrapuptime;
8040 
8041  if (ast_strlen_zero(data)) {
8042  ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface][,wrapuptime]]]]])\n");
8043  return -1;
8044  }
8045 
8046  parse = ast_strdupa(data);
8047 
8048  AST_STANDARD_APP_ARGS(args, parse);
8049 
8050  if (ast_strlen_zero(args.interface)) {
8051  args.interface = ast_strdupa(ast_channel_name(chan));
8052  temppos = strrchr(args.interface, '-');
8053  if (temppos) {
8054  *temppos = '\0';
8055  }
8056  }
8057 
8058  if (!ast_strlen_zero(args.penalty)) {
8059  if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) {
8060  ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
8061  penalty = 0;
8062  }
8063  }
8064 
8065  if (!ast_strlen_zero(args.wrapuptime)) {
8066  tmp = args.wrapuptime;
8067  ast_strip(tmp);
8068  wrapuptime = atoi(tmp);
8069  if (wrapuptime < 0) {
8070  wrapuptime = 0;
8071  }
8072  } else {
8073  wrapuptime = 0;
8074  }
8075 
8076  switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface, NULL, wrapuptime)) {
8077  case RES_OKAY:
8078  if (ast_strlen_zero(args.membername) || !log_membername_as_agent) {
8079  ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "ADDMEMBER", "%s", "");
8080  } else {
8081  ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.membername, "ADDMEMBER", "%s", "");
8082  }
8083  ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
8084  pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
8085  res = 0;
8086  break;
8087  case RES_EXISTS:
8088  ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
8089  pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
8090  res = 0;
8091  break;
8092  case RES_NOSUCHQUEUE:
8093  ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
8094  pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
8095  res = 0;
8096  break;
8097  case RES_OUTOFMEMORY:
8098  ast_log(LOG_ERROR, "Out of memory adding interface %s to queue %s\n", args.interface, args.queuename);
8099  break;
8100  }
8101 
8102  return res;
8103 }
8104 
8105 /*! \brief QueueLog application */
8106 static int ql_exec(struct ast_channel *chan, const char *data)
8107 {
8108  char *parse;
8109 
8111  AST_APP_ARG(queuename);
8112  AST_APP_ARG(uniqueid);
8114  AST_APP_ARG(event);
8115  AST_APP_ARG(params);
8116  );
8117 
8118  if (ast_strlen_zero(data)) {
8119  ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n");
8120  return -1;
8121  }
8122 
8123  parse = ast_strdupa(data);
8124 
8125  AST_STANDARD_APP_ARGS(args, parse);
8126 
8127  if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
8128  || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
8129  ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n");
8130  return -1;
8131  }
8132 
8133  ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event,
8134  "%s", args.params ? args.params : "");
8135 
8136  return 0;
8137 }
8138 
8139 /*! \brief Copy rule from global list into specified queue */
8140 static void copy_rules(struct queue_ent *qe, const char *rulename)
8141 {
8142  struct penalty_rule *pr_iter;
8143  struct rule_list *rl_iter;
8144  const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename;
8146  AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
8147  if (!strcasecmp(rl_iter->name, tmp)) {
8148  break;
8149  }
8150  }
8151  if (rl_iter) {
8152  AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
8153  struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr));
8154  if (!new_pr) {
8155  ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n");
8156  break;
8157  }
8158  new_pr->time = pr_iter->time;
8159  new_pr->max_value = pr_iter->max_value;
8160  new_pr->min_value = pr_iter->min_value;
8161  new_pr->raise_value = pr_iter->raise_value;
8162  new_pr->max_relative = pr_iter->max_relative;
8163  new_pr->min_relative = pr_iter->min_relative;
8164  new_pr->raise_relative = pr_iter->raise_relative;
8165  AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list);
8166  }
8167  }
8169 }
8170 
8171 /*!\brief The starting point for all queue calls
8172  *
8173  * The process involved here is to
8174  * 1. Parse the options specified in the call to Queue()
8175  * 2. Join the queue
8176  * 3. Wait in a loop until it is our turn to try calling a queue member
8177  * 4. Attempt to call a queue member
8178  * 5. If 4. did not result in a bridged call, then check for between
8179  * call options such as periodic announcements etc.
8180  * 6. Try 4 again unless some condition (such as an expiration time) causes us to
8181  * exit the queue.
8182  */
8183 static int queue_exec(struct ast_channel *chan, const char *data)
8184 {
8185  int res=-1;
8186  int ringing=0;
8187  const char *user_priority;
8188  const char *max_penalty_str;
8189  const char *min_penalty_str;
8190  const char *raise_penalty_str;
8191  int prio;
8192  int qcontinue = 0;
8193  int max_penalty, min_penalty, raise_penalty;
8194  enum queue_result reason = QUEUE_UNKNOWN;
8195  /* whether to exit Queue application after the timeout hits */
8196  int tries = 0;
8197  int noption = 0;
8198  char *parse;
8199  int makeannouncement = 0;
8200  int position = 0;
8202  AST_APP_ARG(queuename);
8204  AST_APP_ARG(url);
8205  AST_APP_ARG(announceoverride);
8206  AST_APP_ARG(queuetimeoutstr);
8207  AST_APP_ARG(agi);
8208  AST_APP_ARG(macro);
8209  AST_APP_ARG(gosub);
8210  AST_APP_ARG(rule);
8211  AST_APP_ARG(position);
8212  );
8213  /* Our queue entry */
8214  struct queue_ent qe = { 0 };
8215  struct ast_flags opts = { 0, };
8216  char *opt_args[OPT_ARG_ARRAY_SIZE];
8217  int max_forwards;
8218 
8219  if (ast_strlen_zero(data)) {
8220  ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,macro[,gosub[,rule[,position]]]]]]]]]\n");
8221  return -1;
8222  }
8223 
8224  ast_channel_lock(chan);
8225  max_forwards = ast_max_forwards_get(chan);
8226  ast_channel_unlock(chan);
8227 
8228  if (max_forwards <= 0) {
8229  ast_log(LOG_WARNING, "Channel '%s' cannot enter queue. Max forwards exceeded\n", ast_channel_name(chan));
8230  return -1;
8231  }
8232 
8233  parse = ast_strdupa(data);
8234  AST_STANDARD_APP_ARGS(args, parse);
8235 
8236  ast_debug(1, "queue: %s, options: %s, url: %s, announce: %s, timeout: %s, agi: %s, macro: %s, gosub: %s, rule: %s, position: %s\n",
8237  args.queuename,
8238  S_OR(args.options, ""),
8239  S_OR(args.url, ""),
8240  S_OR(args.announceoverride, ""),
8241  S_OR(args.queuetimeoutstr, ""),
8242  S_OR(args.agi, ""),
8243  S_OR(args.macro, ""),
8244  S_OR(args.gosub, ""),
8245  S_OR(args.rule, ""),
8246  S_OR(args.position, ""));
8247 
8248  if (!ast_strlen_zero(args.options)) {
8249  ast_app_parse_options(queue_exec_options, &opts, opt_args, args.options);
8250  }
8251 
8252  /* Setup our queue entry */
8253  qe.start = time(NULL);
8254 
8255  pbx_builtin_setvar_helper(chan, "ABANDONED", NULL);
8256 
8257  /* set the expire time based on the supplied timeout; */
8258  if (!ast_strlen_zero(args.queuetimeoutstr)) {
8259  qe.expire = qe.start + atoi(args.queuetimeoutstr);
8260  } else {
8261  qe.expire = 0;
8262  }
8263 
8264  /* Get the priority from the variable ${QUEUE_PRIO} */
8265  ast_channel_lock(chan);
8266  user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
8267  if (user_priority) {
8268  if (sscanf(user_priority, "%30d", &prio) == 1) {
8269  ast_debug(1, "%s: Got priority %d from ${QUEUE_PRIO}.\n", ast_channel_name(chan), prio);
8270  } else {
8271  ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
8272  user_priority, ast_channel_name(chan));
8273  prio = 0;
8274  }
8275  } else {
8276  ast_debug(3, "NO QUEUE_PRIO variable found. Using default.\n");
8277  prio = 0;
8278  }
8279 
8280  /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
8281 
8282  if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
8283  if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) {
8284  ast_debug(1, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", ast_channel_name(chan), max_penalty);
8285  } else {
8286  ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
8287  max_penalty_str, ast_channel_name(chan));
8288  max_penalty = INT_MAX;
8289  }
8290  } else {
8291  max_penalty = INT_MAX;
8292  }
8293 
8294  if ((min_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MIN_PENALTY"))) {
8295  if (sscanf(min_penalty_str, "%30d", &min_penalty) == 1) {
8296  ast_debug(1, "%s: Got min penalty %d from ${QUEUE_MIN_PENALTY}.\n", ast_channel_name(chan), min_penalty);
8297  } else {
8298  ast_log(LOG_WARNING, "${QUEUE_MIN_PENALTY}: Invalid value (%s), channel %s.\n",
8299  min_penalty_str, ast_channel_name(chan));
8300  min_penalty = INT_MAX;
8301  }
8302  } else {
8303  min_penalty = INT_MAX;
8304  }
8305 
8306  if ((raise_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_RAISE_PENALTY"))) {
8307  if (sscanf(raise_penalty_str, "%30d", &raise_penalty) == 1) {
8308  ast_debug(1, "%s: Got raise penalty %d from ${QUEUE_RAISE_PENALTY}.\n", ast_channel_name(chan), raise_penalty);
8309  } else {
8310  ast_log(LOG_WARNING, "${QUEUE_RAISE_PENALTY}: Invalid value (%s), channel %s.\n",
8311  raise_penalty_str, ast_channel_name(chan));
8312  raise_penalty = INT_MAX;
8313  }
8314  } else {
8315  raise_penalty = INT_MAX;
8316  }
8317  ast_channel_unlock(chan);
8318 
8319  if (ast_test_flag(&opts, OPT_RINGING)) {
8320  ringing = 1;
8321  }
8322 
8323  if (ringing != 1 && ast_test_flag(&opts, OPT_RING_WHEN_RINGING)) {
8324  qe.ring_when_ringing = 1;
8325  }
8326 
8327  if (ast_test_flag(&opts, OPT_GO_ON)) {
8328  qcontinue = 1;
8329  }
8330 
8331  if (args.position) {
8332  position = atoi(args.position);
8333  if (position < 0) {
8334  ast_log(LOG_WARNING, "Invalid position '%s' given for call to queue '%s'. Assuming no preference for position\n", args.position, args.queuename);
8335  position = 0;
8336  }
8337  }
8338 
8339  ast_debug(1, "queue: %s, expires: %ld, priority: %d\n",
8340  args.queuename, (long)qe.expire, prio);
8341 
8342  qe.chan = chan;
8343  qe.prio = prio;
8344  qe.max_penalty = max_penalty;
8345  qe.min_penalty = min_penalty;
8346  qe.raise_penalty = raise_penalty;
8347  qe.last_pos_said = 0;
8348  qe.last_pos = 0;
8349  qe.last_periodic_announce_time = time(NULL);
8351  qe.valid_digits = 0;
8352  if (join_queue(args.queuename, &qe, &reason, position)) {
8353  ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
8354  set_queue_result(chan, reason);
8355  return 0;
8356  }
8357  ast_assert(qe.parent != NULL);
8358 
8359  ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "ENTERQUEUE", "%s|%s|%d",
8360  S_OR(args.url, ""),
8361  S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
8362  qe.opos);
8363 
8364  /* PREDIAL: Preprocess any callee gosub arguments. */
8365  if (ast_test_flag(&opts, OPT_PREDIAL_CALLEE)
8366  && !ast_strlen_zero(opt_args[OPT_ARG_PREDIAL_CALLEE])) {
8367  ast_replace_subargument_delimiter(opt_args[OPT_ARG_PREDIAL_CALLEE]);
8368  qe.predial_callee = opt_args[OPT_ARG_PREDIAL_CALLEE];
8369  }
8370 
8371  /* PREDIAL: Run gosub on the caller's channel */
8372  if (ast_test_flag(&opts, OPT_PREDIAL_CALLER)
8373  && !ast_strlen_zero(opt_args[OPT_ARG_PREDIAL_CALLER])) {
8374  ast_replace_subargument_delimiter(opt_args[OPT_ARG_PREDIAL_CALLER]);
8375  ast_app_exec_sub(NULL, chan, opt_args[OPT_ARG_PREDIAL_CALLER], 0);
8376  }
8377 
8378  copy_rules(&qe, args.rule);
8379  qe.pr = AST_LIST_FIRST(&qe.qe_rules);
8380 check_turns:
8381  if (ringing) {
8383  } else {
8384  ast_moh_start(chan, qe.moh, NULL);
8385  }
8386 
8387  /* This is the wait loop for callers 2 through maxlen */
8388  res = wait_our_turn(&qe, ringing, &reason);
8389  if (res) {
8390  goto stop;
8391  }
8392 
8393  makeannouncement = qe.parent->announce_to_first_user;
8394 
8395  for (;;) {
8396  /* This is the wait loop for the head caller*/
8397  /* To exit, they may get their call answered; */
8398  /* they may dial a digit from the queue context; */
8399  /* or, they may timeout. */
8400 
8401  /* Leave if we have exceeded our queuetimeout */
8402  if (qe.expire && (time(NULL) >= qe.expire)) {
8403  record_abandoned(&qe);
8404  reason = QUEUE_TIMEOUT;
8405  res = 0;
8406  ast_queue_log(args.queuename, ast_channel_uniqueid(chan),"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld",
8407  qe.pos, qe.opos, (long) (time(NULL) - qe.start));
8408  break;
8409  }
8410 
8411  if (makeannouncement) {
8412  /* Make a position announcement, if enabled */
8413  if (qe.parent->announcefrequency) {
8414  if ((res = say_position(&qe, ringing))) {
8415  goto stop;
8416  }
8417  }
8418  }
8419  makeannouncement = 1;
8420 
8421  /* Make a periodic announcement, if enabled */
8423  if ((res = say_periodic_announcement(&qe, ringing))) {
8424  goto stop;
8425  }
8426  }
8427 
8428  /* Leave if we have exceeded our queuetimeout */
8429  if (qe.expire && (time(NULL) >= qe.expire)) {
8430  record_abandoned(&qe);
8431  reason = QUEUE_TIMEOUT;
8432  res = 0;
8433  ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT",
8434  "%d|%d|%ld", qe.pos, qe.opos, (long) (time(NULL) - qe.start));
8435  break;
8436  }
8437 
8438  /* see if we need to move to the next penalty level for this queue */
8439  while (qe.pr && ((time(NULL) - qe.start) > qe.pr->time)) {
8440  update_qe_rule(&qe);
8441  }
8442 
8443  /* Try calling all queue members for 'timeout' seconds */
8444  res = try_calling(&qe, opts, opt_args, args.announceoverride, args.url, &tries, &noption, args.agi, args.macro, args.gosub, ringing);
8445  if (res) {
8446  goto stop;
8447  }
8448 
8449  if (qe.parent->leavewhenempty) {
8450  int status = 0;
8451  if ((status = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty, qe.raise_penalty, qe.parent->leavewhenempty, 0))) {
8452  record_abandoned(&qe);
8453  reason = QUEUE_LEAVEEMPTY;
8454  ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
8455  res = 0;
8456  break;
8457  }
8458  }
8459 
8460  /* exit after 'timeout' cycle if 'n' option enabled */
8461  if (noption && tries >= ao2_container_count(qe.parent->members)) {
8462  ast_verb(3, "Exiting on time-out cycle\n");
8463  ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT",
8464  "%d|%d|%ld", qe.pos, qe.opos, (long) (time(NULL) - qe.start));
8465  record_abandoned(&qe);
8466  reason = QUEUE_TIMEOUT;
8467  res = 0;
8468  break;
8469  }
8470 
8471 
8472  /* Leave if we have exceeded our queuetimeout */
8473  if (qe.expire && (time(NULL) >= qe.expire)) {
8474  record_abandoned(&qe);
8475  reason = QUEUE_TIMEOUT;
8476  res = 0;
8477  ast_queue_log(qe.parent->name, ast_channel_uniqueid(qe.chan),"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", qe.pos, qe.opos, (long) (time(NULL) - qe.start));
8478  break;
8479  }
8480 
8481  /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
8482  res = wait_a_bit(&qe);
8483  if (res) {
8484  goto stop;
8485  }
8486 
8487  /* If using dynamic realtime members, we should regenerate the member list for this queue */
8489 
8490  /* Since this is a priority queue and
8491  * it is not sure that we are still at the head
8492  * of the queue, go and check for our turn again.
8493  */
8494  if (!is_our_turn(&qe)) {
8495  ast_debug(1, "Darn priorities, going back in queue (%s)!\n", ast_channel_name(qe.chan));
8496  goto check_turns;
8497  }
8498  }
8499 
8500 stop:
8501  if (res) {
8502  if (res < 0) {
8503  if (!qe.handled) {
8504  record_abandoned(&qe);
8505  ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "ABANDON",
8506  "%d|%d|%ld", qe.pos, qe.opos,
8507  (long) (time(NULL) - qe.start));
8508  res = -1;
8509  } else if (reason == QUEUE_LEAVEEMPTY) {
8510  /* Return back to dialplan, don't hang up */
8511  res = 0;
8512  } else if (qcontinue) {
8513  reason = QUEUE_CONTINUE;
8514  res = 0;
8515  }
8516  } else if (qe.valid_digits) {
8517  ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHKEY",
8518  "%s|%d|%d|%ld", qe.digits, qe.pos, qe.opos, (long) (time(NULL) - qe.start));
8519  }
8520  }
8521 
8522  /* Don't allow return code > 0 */
8523  if (res >= 0) {
8524  res = 0;
8525  if (ringing) {
8526  ast_indicate(chan, -1);
8527  } else {
8528  ast_moh_stop(chan);
8529  }
8530  ast_stopstream(chan);
8531  }
8532 
8534 
8535  leave_queue(&qe);
8536  if (reason != QUEUE_UNKNOWN)
8537  set_queue_result(chan, reason);
8538 
8539  /*
8540  * every queue_ent is given a reference to it's parent
8541  * call_queue when it joins the queue. This ref must be taken
8542  * away right before the queue_ent is destroyed. In this case
8543  * the queue_ent is about to be returned on the stack
8544  */
8545  qe.parent = queue_unref(qe.parent);
8546 
8547  return res;
8548 }
8549 
8550 /*!
8551  * \brief create interface var with all queue details.
8552  * \retval 0 on success
8553  * \retval -1 on error
8554 */
8555 static int queue_function_var(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
8556 {
8557  int res = -1;
8558  struct call_queue *q;
8559  char interfacevar[256] = "";
8560  float sl = 0;
8561 
8562  if (ast_strlen_zero(data)) {
8563  ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
8564  return -1;
8565  }
8566 
8567  if ((q = find_load_queue_rt_friendly(data))) {
8568  ao2_lock(q);
8569  if (q->setqueuevar) {
8570  sl = 0;
8571  res = 0;
8572 
8573  if (q->callscompleted > 0) {
8574  sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
8575  }
8576 
8577  snprintf(interfacevar, sizeof(interfacevar),
8578  "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
8580 
8581  pbx_builtin_setvar_multiple(chan, interfacevar);
8582  }
8583 
8584  ao2_unlock(q);
8585  queue_t_unref(q, "Done with QUEUE() function");
8586  } else {
8587  ast_log(LOG_WARNING, "queue %s was not found\n", data);
8588  }
8589 
8590  snprintf(buf, len, "%d", res);
8591 
8592  return 0;
8593 }
8594 
8595 /*!
8596  * \brief Check if a given queue exists
8597  *
8598  */
8599 static int queue_function_exists(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
8600 {
8601  struct call_queue *q;
8602 
8603  buf[0] = '\0';
8604 
8605  if (ast_strlen_zero(data)) {
8606  ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
8607  return -1;
8608  }
8609  q = find_load_queue_rt_friendly(data);
8610  snprintf(buf, len, "%d", q != NULL? 1 : 0);
8611  if (q) {
8612  queue_t_unref(q, "Done with temporary reference in QUEUE_EXISTS()");
8613  }
8614 
8615  return 0;
8616 }
8617 
8618 static struct member *get_interface_helper(struct call_queue *q, const char *interface)
8619 {
8620  struct member *m;
8621 
8622  if (ast_strlen_zero(interface)) {
8623  ast_log(LOG_ERROR, "QUEUE_MEMBER: Missing required interface argument.\n");
8624  return NULL;
8625  }
8626 
8627  m = interface_exists(q, interface);
8628  if (!m) {
8629  ast_log(LOG_ERROR, "Queue member interface '%s' not in queue '%s'.\n",
8630  interface, q->name);
8631  }
8632  return m;
8633 }
8634 
8635 /*!
8636  * \brief Get number either busy / free / ready or total members of a specific queue
8637  * \brief Get or set member properties penalty / paused / ringinuse
8638  * \retval number of members (busy / free / ready / total) or member info (penalty / paused / ringinuse)
8639  * \retval -1 on error
8640  */
8641 static int queue_function_mem_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
8642 {
8643  int count = 0;
8644  struct member *m;
8645  struct ao2_iterator mem_iter;
8646  struct call_queue *q;
8647 
8649  AST_APP_ARG(queuename);
8650  AST_APP_ARG(option);
8651  AST_APP_ARG(interface);
8652  );
8653  /* Make sure the returned value on error is zero length string. */
8654  buf[0] = '\0';
8655 
8656  if (ast_strlen_zero(data)) {
8658  "Missing required argument. %s(<queuename>,<option>[,<interface>])\n",
8659  cmd);
8660  return -1;
8661  }
8662 
8663  AST_STANDARD_APP_ARGS(args, data);
8664 
8665  if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.option)) {
8667  "Missing required argument. %s(<queuename>,<option>[,<interface>])\n",
8668  cmd);
8669  return -1;
8670  }
8671 
8672  if ((q = find_load_queue_rt_friendly(args.queuename))) {
8673  ao2_lock(q);
8674  if (!strcasecmp(args.option, "logged")) {
8675  mem_iter = ao2_iterator_init(q->members, 0);
8676  while ((m = ao2_iterator_next(&mem_iter))) {
8677  /* Count the agents who are logged in and presently answering calls */
8678  if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
8679  count++;
8680  }
8681  ao2_ref(m, -1);
8682  }
8683  ao2_iterator_destroy(&mem_iter);
8684  } else if (!strcasecmp(args.option, "free")) {
8685  mem_iter = ao2_iterator_init(q->members, 0);
8686  while ((m = ao2_iterator_next(&mem_iter))) {
8687  /* Count the agents who are logged in and presently answering calls */
8688  if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused)) {
8689  count++;
8690  }
8691  ao2_ref(m, -1);
8692  }
8693  ao2_iterator_destroy(&mem_iter);
8694  } else if (!strcasecmp(args.option, "ready")) {
8695  time_t now;
8696  time(&now);
8697  mem_iter = ao2_iterator_init(q->members, 0);
8698  while ((m = ao2_iterator_next(&mem_iter))) {
8699  /* Count the agents who are logged in, not paused and not wrapping up */
8700  if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused) &&
8701  !(m->lastcall && get_wrapuptime(q, m) && ((now - get_wrapuptime(q, m)) < m->lastcall))) {
8702  count++;
8703  }
8704  ao2_ref(m, -1);
8705  }
8706  ao2_iterator_destroy(&mem_iter);
8707  } else if (!strcasecmp(args.option, "count")) {
8708  count = ao2_container_count(q->members);
8709  } else if (!strcasecmp(args.option, "penalty")) {
8710  m = get_interface_helper(q, args.interface);
8711  if (m) {
8712  count = m->penalty;
8713  ao2_ref(m, -1);
8714  }
8715  } else if (!strcasecmp(args.option, "paused")) {
8716  m = get_interface_helper(q, args.interface);
8717  if (m) {
8718  count = m->paused;
8719  ao2_ref(m, -1);
8720  }
8721  } else if ((!strcasecmp(args.option, "ignorebusy") /* ignorebusy is legacy */
8722  || !strcasecmp(args.option, "ringinuse"))) {
8723  m = get_interface_helper(q, args.interface);
8724  if (m) {
8725  count = m->ringinuse;
8726  ao2_ref(m, -1);
8727  }
8728  } else {
8729  ast_log(LOG_ERROR, "%s: Invalid option '%s' provided.\n", cmd, args.option);
8730  }
8731  ao2_unlock(q);
8732  queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()");
8733  } else {
8734  ast_log(LOG_WARNING, "queue %s was not found\n", args.queuename);
8735  }
8736 
8737  snprintf(buf, len, "%d", count);
8738 
8739  return 0;
8740 }
8741 
8742 /*! \brief Dialplan function QUEUE_MEMBER() Sets the members penalty / paused / ringinuse. */
8743 static int queue_function_mem_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
8744 {
8745  int memvalue;
8746 
8748  AST_APP_ARG(queuename);
8749  AST_APP_ARG(option);
8750  AST_APP_ARG(interface);
8751  );
8752 
8753  if (ast_strlen_zero(data)) {
8755  "Missing required argument. %s([<queuename>],<option>,<interface>)\n",
8756  cmd);
8757  return -1;
8758  }
8759 
8760  AST_STANDARD_APP_ARGS(args, data);
8761 
8762  if (ast_strlen_zero(args.option)
8763  || ast_strlen_zero(args.interface)) {
8765  "Missing required argument. %s([<queuename>],<option>,<interface>)\n",
8766  cmd);
8767  return -1;
8768  }
8769 
8770  /*
8771  * If queuename is empty then the option will be
8772  * set for the interface in all queues.
8773  */
8774 
8775  memvalue = atoi(value);
8776  if (!strcasecmp(args.option, "penalty")) {
8777  if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, memvalue)) {
8778  ast_log(LOG_ERROR, "Invalid interface, queue, or penalty\n");
8779  return -1;
8780  }
8781  } else if (!strcasecmp(args.option, "paused")) {
8782  memvalue = (memvalue <= 0) ? 0 : 1;
8783  if (set_member_paused(args.queuename, args.interface, NULL, memvalue)) {
8784  ast_log(LOG_ERROR, "Invalid interface or queue\n");
8785  return -1;
8786  }
8787  } else if (!strcasecmp(args.option, "ignorebusy") /* ignorebusy is legacy */
8788  || !strcasecmp(args.option, "ringinuse")) {
8789  memvalue = (memvalue <= 0) ? 0 : 1;
8790  if (set_member_value(args.queuename, args.interface, MEMBER_RINGINUSE, memvalue)) {
8791  ast_log(LOG_ERROR, "Invalid interface or queue\n");
8792  return -1;
8793  }
8794  } else {
8795  ast_log(LOG_ERROR, "%s: Invalid option '%s' provided.\n", cmd, args.option);
8796  return -1;
8797  }
8798  return 0;
8799 }
8800 
8801 /*!
8802  * \brief Get the total number of members in a specific queue (Deprecated)
8803  * \retval number of members
8804  * \retval -1 on error
8805 */
8806 static int queue_function_qac_dep(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
8807 {
8808  int count = 0;
8809  struct member *m;
8810  struct call_queue *q;
8811  struct ao2_iterator mem_iter;
8812  static int depflag = 1;
8813 
8814  if (depflag) {
8815  depflag = 0;
8816  ast_log(LOG_NOTICE, "The function QUEUE_MEMBER_COUNT has been deprecated in favor of the QUEUE_MEMBER function and will not be in further releases.\n");
8817  }
8818 
8819  if (ast_strlen_zero(data)) {
8820  ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
8821  return -1;
8822  }
8823 
8824  if ((q = find_load_queue_rt_friendly(data))) {
8825  ao2_lock(q);
8826  mem_iter = ao2_iterator_init(q->members, 0);
8827  while ((m = ao2_iterator_next(&mem_iter))) {
8828  /* Count the agents who are logged in and presently answering calls */
8829  if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
8830  count++;
8831  }
8832  ao2_ref(m, -1);
8833  }
8834  ao2_iterator_destroy(&mem_iter);
8835  ao2_unlock(q);
8836  queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER_COUNT");
8837  } else {
8838  ast_log(LOG_WARNING, "queue %s was not found\n", data);
8839  }
8840 
8841  snprintf(buf, len, "%d", count);
8842 
8843  return 0;
8844 }
8845 
8846 /*! \brief Dialplan function QUEUE_GET_CHANNEL() Get caller channel waiting at specified position in the queue */
8847 static int queue_function_queuegetchannel(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
8848 {
8849  int position;
8850  char *parse;
8851  struct call_queue *q;
8852  struct ast_variable *var;
8853 
8855  AST_APP_ARG(queuename);
8856  AST_APP_ARG(position);
8857  );
8858 
8859  buf[0] = '\0';
8860 
8861  if (ast_strlen_zero(data)) {
8862  ast_log(LOG_ERROR, "Missing argument. QUEUE_GET_CHANNEL(<queuename>,<position>)\n");
8863  return -1;
8864  }
8865 
8866  parse = ast_strdupa(data);
8867  AST_STANDARD_APP_ARGS(args, parse);
8868 
8869  if (ast_strlen_zero(args.queuename)) {
8870  ast_log (LOG_ERROR, "The <queuename> parameter is required.\n");
8871  return -1;
8872  }
8873 
8874  if (ast_strlen_zero(args.position)) {
8875  position = 1;
8876  } else {
8877  if (sscanf(args.position, "%30d", &position) != 1) {
8878  ast_log (LOG_ERROR, "<position> parameter must be an integer.\n");
8879  return -1;
8880  }
8881  if (position < 1) {
8882  ast_log (LOG_ERROR, "<position> parameter must be an integer greater than zero.\n");
8883  return -1;
8884  }
8885  }
8886 
8887  {
8888  struct call_queue tmpq = {
8889  .name = args.queuename,
8890  };
8891 
8892  q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_GET_CHANNEL()");
8893  }
8894  if (q) {
8895  ao2_lock(q);
8896  if (q->count >= position) {
8897  struct queue_ent *qe;
8898 
8899  for (qe = q->head; qe; qe = qe->next) {
8900  if (qe->pos == position) {
8901  ast_copy_string(buf, ast_channel_name(qe->chan), len);
8902  break;
8903  }
8904  }
8905  }
8906  ao2_unlock(q);
8907  queue_t_unref(q, "Done with reference in QUEUE_GET_CHANNEL()");
8908  return 0;
8909  }
8910 
8911  var = ast_load_realtime("queues", "name", args.queuename, SENTINEL);
8912  if (var) {
8913  /* if the queue is realtime but was not found in memory, this
8914  * means that the queue had been deleted from memory since it was
8915  * "dead."
8916  */
8917  ast_variables_destroy(var);
8918  return 0;
8919  }
8920 
8921  ast_log(LOG_WARNING, "queue %s was not found\n", args.queuename);
8922  return 0;
8923 }
8924 
8925 /*! \brief Dialplan function QUEUE_WAITING_COUNT() Get number callers waiting in a specific queue */
8926 static int queue_function_queuewaitingcount(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
8927 {
8928  int count = 0;
8929  struct call_queue *q, tmpq = {
8930  .name = data,
8931  };
8932  struct ast_variable *var = NULL;
8933 
8934  buf[0] = '\0';
8935 
8936  if (ast_strlen_zero(data)) {
8937  ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n");
8938  return -1;
8939  }
8940 
8941  if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_WAITING_COUNT()"))) {
8942  ao2_lock(q);
8943  count = q->count;
8944  ao2_unlock(q);
8945  queue_t_unref(q, "Done with reference in QUEUE_WAITING_COUNT()");
8946  } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) {
8947  /* if the queue is realtime but was not found in memory, this
8948  * means that the queue had been deleted from memory since it was
8949  * "dead." This means it has a 0 waiting count
8950  */
8951  count = 0;
8952  ast_variables_destroy(var);
8953  } else {
8954  ast_log(LOG_WARNING, "queue %s was not found\n", data);
8955  }
8956 
8957  snprintf(buf, len, "%d", count);
8958 
8959  return 0;
8960 }
8961 
8962 /*! \brief Dialplan function QUEUE_MEMBER_LIST() Get list of members in a specific queue */
8963 static int queue_function_queuememberlist(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
8964 {
8965  struct call_queue *q;
8966  struct member *m;
8967 
8968  /* Ensure an otherwise empty list doesn't return garbage */
8969  buf[0] = '\0';
8970 
8971  if (ast_strlen_zero(data)) {
8972  ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
8973  return -1;
8974  }
8975 
8976  if ((q = find_load_queue_rt_friendly(data))) {
8977  int buflen = 0, count = 0;
8978  struct ao2_iterator mem_iter;
8979 
8980  ao2_lock(q);
8981  mem_iter = ao2_iterator_init(q->members, 0);
8982  while ((m = ao2_iterator_next(&mem_iter))) {
8983  /* strcat() is always faster than printf() */
8984  if (count++) {
8985  strncat(buf + buflen, ",", len - buflen - 1);
8986  buflen++;
8987  }
8988  strncat(buf + buflen, m->interface, len - buflen - 1);
8989  buflen += strlen(m->interface);
8990  /* Safeguard against overflow (negative length) */
8991  if (buflen >= len - 2) {
8992  ao2_ref(m, -1);
8993  ast_log(LOG_WARNING, "Truncating list\n");
8994  break;
8995  }
8996  ao2_ref(m, -1);
8997  }
8998  ao2_iterator_destroy(&mem_iter);
8999  ao2_unlock(q);
9000  queue_t_unref(q, "Done with QUEUE_MEMBER_LIST()");
9001  } else
9002  ast_log(LOG_WARNING, "queue %s was not found\n", data);
9003 
9004  /* We should already be terminated, but let's make sure. */
9005  buf[len - 1] = '\0';
9006 
9007  return 0;
9008 }
9009 
9010 /*! \brief Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty. */
9011 static int queue_function_memberpenalty_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
9012 {
9013  int penalty;
9015  AST_APP_ARG(queuename);
9016  AST_APP_ARG(interface);
9017  );
9018  /* Make sure the returned value on error is NULL. */
9019  buf[0] = '\0';
9020 
9021  if (ast_strlen_zero(data)) {
9022  ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9023  return -1;
9024  }
9025 
9026  AST_STANDARD_APP_ARGS(args, data);
9027 
9028  if (args.argc < 2) {
9029  ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9030  return -1;
9031  }
9032 
9033  penalty = get_member_penalty (args.queuename, args.interface);
9034 
9035  if (penalty >= 0) { /* remember that buf is already '\0' */
9036  snprintf (buf, len, "%d", penalty);
9037  }
9038 
9039  return 0;
9040 }
9041 
9042 /*! \brief Dialplan function QUEUE_MEMBER_PENALTY() Sets the members penalty. */
9043 static int queue_function_memberpenalty_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
9044 {
9045  int penalty;
9047  AST_APP_ARG(queuename);
9048  AST_APP_ARG(interface);
9049  );
9050 
9051  if (ast_strlen_zero(data)) {
9052  ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9053  return -1;
9054  }
9055 
9056  AST_STANDARD_APP_ARGS(args, data);
9057 
9058  if (args.argc < 2) {
9059  ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9060  return -1;
9061  }
9062 
9063  penalty = atoi(value);
9064 
9065  if (ast_strlen_zero(args.interface)) {
9066  ast_log (LOG_ERROR, "<interface> parameter can't be null\n");
9067  return -1;
9068  }
9069 
9070  /* if queuename = NULL then penalty will be set for interface in all the queues. */
9071  if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, penalty)) {
9072  ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n");
9073  return -1;
9074  }
9075 
9076  return 0;
9077 }
9078 
9080  .name = "QUEUE_EXISTS",
9081  .read = queue_function_exists,
9082 };
9083 
9085  .name = "QUEUE_VARIABLES",
9086  .read = queue_function_var,
9087 };
9088 
9090  .name = "QUEUE_MEMBER",
9091  .read = queue_function_mem_read,
9092  .write = queue_function_mem_write,
9093 };
9094 
9096  .name = "QUEUE_MEMBER_COUNT",
9097  .read = queue_function_qac_dep,
9098 };
9099 
9101  .name = "QUEUE_GET_CHANNEL",
9103 };
9104 
9106  .name = "QUEUE_WAITING_COUNT",
9108 };
9109 
9111  .name = "QUEUE_MEMBER_LIST",
9113 };
9114 
9116  .name = "QUEUE_MEMBER_PENALTY",
9119 };
9120 
9121 /*! Reset the global queue rules parameters even if there is no "general" section of queuerules.conf */
9123 {
9124  realtime_rules = 0;
9125 }
9126 
9127 /*! Set the global queue rules parameters as defined in the "general" section of queuerules.conf */
9129 {
9130  const char *general_val = NULL;
9131  if ((general_val = ast_variable_retrieve(cfg, "general", "realtime_rules"))) {
9132  realtime_rules = ast_true(general_val);
9133  }
9134 }
9135 
9136 /*! \brief Reload the rules defined in queuerules.conf
9137  *
9138  * \param reload If 1, then only process queuerules.conf if the file
9139  * has changed since the last time we inspected it.
9140  * \return Always returns AST_MODULE_LOAD_SUCCESS
9141  */
9143 {
9144  struct ast_config *cfg;
9145  struct rule_list *rl_iter, *new_rl;
9146  struct penalty_rule *pr_iter;
9147  char *rulecat = NULL;
9148  struct ast_variable *rulevar = NULL;
9149  struct ast_flags config_flags = { (reload && !realtime_rules) ? CONFIG_FLAG_FILEUNCHANGED : 0 };
9150 
9151  if (!(cfg = ast_config_load("queuerules.conf", config_flags))) {
9152  ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n");
9153  return AST_MODULE_LOAD_SUCCESS;
9154  } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
9155  ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n");
9156  return AST_MODULE_LOAD_SUCCESS;
9157  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
9158  ast_log(LOG_ERROR, "Config file queuerules.conf is in an invalid format. Aborting.\n");
9159  return AST_MODULE_LOAD_SUCCESS;
9160  }
9161 
9163  while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) {
9164  while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list)))
9165  ast_free(pr_iter);
9166  ast_free(rl_iter);
9167  }
9169  while ((rulecat = ast_category_browse(cfg, rulecat))) {
9170  if (!strcasecmp(rulecat, "general")) {
9172  continue;
9173  }
9174  if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
9176  ast_config_destroy(cfg);
9177  return AST_MODULE_LOAD_DECLINE;
9178  } else {
9179  ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
9180  AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
9181  for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next)
9182  if(!strcasecmp(rulevar->name, "penaltychange"))
9183  insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno);
9184  else
9185  ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno);
9186  }
9187  }
9188 
9189  ast_config_destroy(cfg);
9190 
9191  if (realtime_rules && load_realtime_rules()) {
9193  return AST_MODULE_LOAD_DECLINE;
9194  }
9195 
9197  return AST_MODULE_LOAD_SUCCESS;
9198 }
9199 
9200 /*! Always set the global queue defaults, even if there is no "general" section in queues.conf */
9201 static void queue_reset_global_params(void)
9202 {
9203  queue_persistent_members = 0;
9204  autofill_default = 0;
9205  montype_default = 0;
9206  shared_lastcall = 0;
9207  negative_penalty_invalid = 0;
9208  log_membername_as_agent = 0;
9209 }
9210 
9211 /*! Set the global queue parameters as defined in the "general" section of queues.conf */
9212 static void queue_set_global_params(struct ast_config *cfg)
9213 {
9214  const char *general_val = NULL;
9215  if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) {
9216  queue_persistent_members = ast_true(general_val);
9217  }
9218  if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) {
9219  autofill_default = ast_true(general_val);
9220  }
9221  if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) {
9222  if (!strcasecmp(general_val, "mixmonitor"))
9223  montype_default = 1;
9224  }
9225  if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall"))) {
9226  shared_lastcall = ast_true(general_val);
9227  }
9228  if ((general_val = ast_variable_retrieve(cfg, "general", "negative_penalty_invalid"))) {
9229  negative_penalty_invalid = ast_true(general_val);
9230  }
9231  if ((general_val = ast_variable_retrieve(cfg, "general", "log_membername_as_agent"))) {
9232  log_membername_as_agent = ast_true(general_val);
9233  }
9234 }
9235 
9236 /*! \brief reload information pertaining to a single member
9237  *
9238  * This function is called when a member = line is encountered in
9239  * queues.conf.
9240  *
9241  * \param memberdata The part after member = in the config file
9242  * \param q The queue to which this member belongs
9243  */
9244 static void reload_single_member(const char *memberdata, struct call_queue *q)
9245 {
9246  char *membername, *interface, *state_interface, *tmp;
9247  char *parse;
9248  struct member *cur, *newm;
9249  struct member tmpmem;
9250  int penalty;
9251  int ringinuse;
9252  int wrapuptime;
9254  AST_APP_ARG(interface);
9255  AST_APP_ARG(penalty);
9256  AST_APP_ARG(membername);
9257  AST_APP_ARG(state_interface);
9258  AST_APP_ARG(ringinuse);
9259  AST_APP_ARG(wrapuptime);
9260  );
9261 
9262  if (ast_strlen_zero(memberdata)) {
9263  ast_log(LOG_WARNING, "Empty queue member definition. Moving on!\n");
9264  return;
9265  }
9266 
9267  /* Add a new member */
9268  parse = ast_strdupa(memberdata);
9269 
9270  AST_STANDARD_APP_ARGS(args, parse);
9271 
9272  interface = args.interface;
9273  if (!ast_strlen_zero(args.penalty)) {
9274  tmp = args.penalty;
9275  ast_strip(tmp);
9276  penalty = atoi(tmp);
9277  if (penalty < 0) {
9278  penalty = 0;
9279  }
9280  } else {
9281  penalty = 0;
9282  }
9283 
9284  if (!ast_strlen_zero(args.membername)) {
9285  membername = args.membername;
9286  ast_strip(membername);
9287  } else {
9288  membername = interface;
9289  }
9290 
9291  if (!ast_strlen_zero(args.state_interface)) {
9292  state_interface = args.state_interface;
9293  ast_strip(state_interface);
9294  } else {
9295  state_interface = interface;
9296  }
9297 
9298  if (!ast_strlen_zero(args.ringinuse)) {
9299  tmp = args.ringinuse;
9300  ast_strip(tmp);
9301  if (ast_true(tmp)) {
9302  ringinuse = 1;
9303  } else if (ast_false(tmp)) {
9304  ringinuse = 0;
9305  } else {
9306  ast_log(LOG_ERROR, "Member %s has an invalid ringinuse value. Using %s ringinuse value.\n",
9307  membername, q->name);
9308  ringinuse = q->ringinuse;
9309  }
9310  } else {
9311  ringinuse = q->ringinuse;
9312  }
9313 
9314  if (!ast_strlen_zero(args.wrapuptime)) {
9315  tmp = args.wrapuptime;
9316  ast_strip(tmp);
9317  wrapuptime = atoi(tmp);
9318  if (wrapuptime < 0) {
9319  wrapuptime = 0;
9320  }
9321  } else {
9322  wrapuptime = 0;
9323  }
9324 
9325  /* Find the old position in the list */
9326  ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
9327  cur = ao2_find(q->members, &tmpmem, OBJ_POINTER);
9328 
9329  if ((newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface, ringinuse, wrapuptime))) {
9330  newm->wrapuptime = wrapuptime;
9331  if (cur) {
9332  /* Round Robin Queue Position must be copied if this is replacing an existing member */
9333  ao2_lock(q->members);
9334  newm->queuepos = cur->queuepos;
9335  ao2_link(q->members, newm);
9336  ao2_unlink(q->members, cur);
9337  ao2_unlock(q->members);
9338  } else {
9339  /* Otherwise we need to add using the function that will apply a round robin queue position manually. */
9340  member_add_to_queue(q, newm);
9341  }
9342  ao2_ref(newm, -1);
9343  }
9344  newm = NULL;
9345 
9346  if (cur) {
9347  ao2_ref(cur, -1);
9348  }
9349 }
9350 
9351 static int mark_member_dead(void *obj, void *arg, int flags)
9352 {
9353  struct member *member = obj;
9354  if (!member->dynamic && !member->realtime) {
9355  member->delme = 1;
9356  }
9357  return 0;
9358 }
9359 
9360 static int kill_dead_members(void *obj, void *arg, int flags)
9361 {
9362  struct member *member = obj;
9363 
9364  if (!member->delme) {
9365  member->status = get_queue_member_status(member);
9366  return 0;
9367  } else {
9368  return CMP_MATCH;
9369  }
9370 }
9371 
9372 /*! \brief Reload information pertaining to a particular queue
9373  *
9374  * Once we have isolated a queue within reload_queues, we call this. This will either
9375  * reload information for the queue or if we're just reloading member information, we'll just
9376  * reload that without touching other settings within the queue
9377  *
9378  * \param cfg The configuration which we are reading
9379  * \param mask Tells us what information we need to reload
9380  * \param queuename The name of the queue we are reloading information from
9381  * \retval void
9382  */
9383 static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask, const char *queuename)
9384 {
9385  int new;
9386  struct call_queue *q = NULL;
9387  struct member *member;
9388  /*We're defining a queue*/
9389  struct call_queue tmpq = {
9390  .name = queuename,
9391  };
9392  const char *tmpvar;
9393  const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
9394  const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER);
9395  int prev_weight = 0;
9396  struct ast_variable *var;
9397  struct ao2_iterator mem_iter;
9398 
9399  if (!(q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find queue for reload"))) {
9400  if (queue_reload) {
9401  /* Make one then */
9402  if (!(q = alloc_queue(queuename))) {
9403  return;
9404  }
9405  } else {
9406  /* Since we're not reloading queues, this means that we found a queue
9407  * in the configuration file which we don't know about yet. Just return.
9408  */
9409  return;
9410  }
9411  new = 1;
9412  } else {
9413  new = 0;
9414  }
9415 
9416  if (!new) {
9417  ao2_lock(q);
9418  prev_weight = q->weight ? 1 : 0;
9419  }
9420  /* Check if we already found a queue with this name in the config file */
9421  if (q->found) {
9422  ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", queuename);
9423  if (!new) {
9424  /* It should be impossible to *not* hit this case*/
9425  ao2_unlock(q);
9426  }
9427  queue_t_unref(q, "We exist! Expiring temporary pointer");
9428  return;
9429  }
9430  /* Due to the fact that the "linear" strategy will have a different allocation
9431  * scheme for queue members, we must devise the queue's strategy before other initializations.
9432  * To be specific, the linear strategy needs to function like a linked list, meaning the ao2
9433  * container used will have only a single bucket instead of the typical number.
9434  */
9435  if (queue_reload) {
9436  if ((tmpvar = ast_variable_retrieve(cfg, queuename, "strategy"))) {
9437  q->strategy = strat2int(tmpvar);
9438  if (q->strategy < 0) {
9439  ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
9440  tmpvar, q->name);
9442  }
9443  } else {
9445  }
9446  init_queue(q);
9447  }
9448  if (member_reload) {
9450  q->found = 1;
9451  }
9452 
9453  /* On the first pass we just read the parameters of the queue */
9454  for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
9455  if (queue_reload && strcasecmp(var->name, "member")) {
9456  queue_set_param(q, var->name, var->value, var->lineno, 1);
9457  }
9458  }
9459 
9460  /* On the second pass, we read members */
9461  for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
9462  if (member_reload && !strcasecmp(var->name, "member")) {
9463  reload_single_member(var->value, q);
9464  }
9465  }
9466 
9467  /* Update ringinuse for dynamic members */
9468  if (member_reload) {
9469  ao2_lock(q->members);
9471  while ((member = ao2_iterator_next(&mem_iter))) {
9472  if (member->dynamic) {
9473  member->ringinuse = q->ringinuse;
9474  }
9475  ao2_ref(member, -1);
9476  }
9477  ao2_iterator_destroy(&mem_iter);
9478  ao2_unlock(q->members);
9479  }
9480 
9481  /* At this point, we've determined if the queue has a weight, so update use_weight
9482  * as appropriate
9483  */
9484  if (!q->weight && prev_weight) {
9485  ast_atomic_fetchadd_int(&use_weight, -1);
9486  } else if (q->weight && !prev_weight) {
9487  ast_atomic_fetchadd_int(&use_weight, +1);
9488  }
9489 
9490  /* Free remaining members marked as delme */
9491  if (member_reload) {
9492  ao2_lock(q->members);
9495  ao2_unlock(q->members);
9496  }
9497 
9498  if (new) {
9499  queues_t_link(queues, q, "Add queue to container");
9500  } else {
9501  ao2_unlock(q);
9502  }
9503  queue_t_unref(q, "Expiring creation reference");
9504 }
9505 
9506 static int mark_unfound(void *obj, void *arg, int flags)
9507 {
9508  struct call_queue *q = obj;
9509  char *queuename = arg;
9510  if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
9511  q->found = 0;
9512  }
9513  return 0;
9514 }
9515 
9516 static int kill_if_unfound(void *obj, void *arg, int flags)
9517 {
9518  struct call_queue *q = obj;
9519  char *queuename = arg;
9520  if (!q->realtime && !q->found && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
9521  q->dead = 1;
9522  return CMP_MATCH;
9523  } else {
9524  return 0;
9525  }
9526 }
9527 
9528 /*! \brief reload the queues.conf file
9529  *
9530  * This function reloads the information in the general section of the queues.conf
9531  * file and potentially more, depending on the value of mask.
9532  *
9533  * \param reload 0 if we are calling this the first time, 1 every other time
9534  * \param mask Gives flags telling us what information to actually reload
9535  * \param queuename If set to a non-zero string, then only reload information from
9536  * that particular queue. Otherwise inspect all queues
9537  * \retval -1 Failure occurred
9538  * \retval 0 All clear!
9539  */
9540 static int reload_queues(int reload, struct ast_flags *mask, const char *queuename)
9541 {
9542  struct ast_config *cfg;
9543  char *cat;
9544  struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
9545  const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
9546 
9547  if (!(cfg = ast_config_load("queues.conf", config_flags))) {
9548  ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
9549  return -1;
9550  } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
9551  return 0;
9552  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
9553  ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format. Aborting.\n");
9554  return -1;
9555  }
9556 
9557  /* We've made it here, so it looks like we're doing operations on all queues. */
9558  ao2_lock(queues);
9559 
9560  /* Mark non-realtime queues not found at the beginning. */
9561  ao2_callback(queues, OBJ_NODATA, mark_unfound, (char *) queuename);
9562 
9563  /* Chug through config file. */
9564  cat = NULL;
9566  while ((cat = ast_category_browse(cfg, cat)) ) {
9567  if (!strcasecmp(cat, "general") && queue_reload) {
9569  continue;
9570  }
9571  if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename))
9572  reload_single_queue(cfg, mask, cat);
9573  }
9574 
9575  ast_config_destroy(cfg);
9576  if (queue_reload) {
9577  /* Unlink and mark dead all non-realtime queues that were not found in the configuration file. */
9578  ao2_callback(queues, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK | OBJ_NOLOCK, kill_if_unfound, (char *) queuename);
9579  }
9580  ao2_unlock(queues);
9581  return 0;
9582 }
9583 
9584 /*! \brief Facilitates resetting statistics for a queue
9585  *
9586  * This function actually does not reset any statistics, but
9587  * rather finds a call_queue struct which corresponds to the
9588  * passed-in queue name and passes that structure to the
9589  * clear_queue function. If no queuename is passed in, then
9590  * all queues will have their statistics reset.
9591  *
9592  * \param queuename The name of the queue to reset the statistics
9593  * for. If this is NULL or zero-length, then this means to reset
9594  * the statistics for all queues
9595  * \retval void
9596  */
9597 static int clear_stats(const char *queuename)
9598 {
9599  struct call_queue *q;
9600  struct ao2_iterator queue_iter;
9601 
9602  queue_iter = ao2_iterator_init(queues, 0);
9603  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
9604  ao2_lock(q);
9605  if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename))
9606  clear_queue(q);
9607  ao2_unlock(q);
9608  queue_t_unref(q, "Done with iterator");
9609  }
9610  ao2_iterator_destroy(&queue_iter);
9611  return 0;
9612 }
9613 
9614 /*! \brief The command center for all reload operations
9615  *
9616  * Whenever any piece of queue information is to be reloaded, this function
9617  * is called. It interprets the flags set in the mask parameter and acts
9618  * based on how they are set.
9619  *
9620  * \param reload True if we are reloading information, false if we are loading
9621  * information for the first time.
9622  * \param mask A bitmask which tells the handler what actions to take
9623  * \param queuename The name of the queue on which we wish to take action
9624  * \retval 0 All reloads were successful
9625  * \retval non-zero There was a failure
9626  */
9627 static int reload_handler(int reload, struct ast_flags *mask, const char *queuename)
9628 {
9629  int res = 0;
9630 
9631  if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) {
9632  res |= reload_queue_rules(reload);
9633  }
9634  if (ast_test_flag(mask, QUEUE_RESET_STATS)) {
9635  res |= clear_stats(queuename);
9636  }
9638  res |= reload_queues(reload, mask, queuename);
9639  }
9640  return res;
9641 }
9642 
9643 /*! \brief direct ouput to manager or cli with proper terminator */
9644 static void do_print(struct mansession *s, int fd, const char *str)
9645 {
9646  if (s) {
9647  astman_append(s, "%s\r\n", str);
9648  } else {
9649  ast_cli(fd, "%s\n", str);
9650  }
9651 }
9652 
9653 /*! \brief Print a single queue to AMI or the CLI */
9654 static void print_queue(struct mansession *s, int fd, struct call_queue *q)
9655 {
9656  float sl;
9657  float sl2;
9658  struct ao2_iterator mem_iter;
9659  struct ast_str *out = ast_str_alloca(512);
9660  time_t now = time(NULL);
9661 
9662  ast_str_set(&out, 0, "%s has %d calls (max ", q->name, q->count);
9663  if (q->maxlen) {
9664  ast_str_append(&out, 0, "%d", q->maxlen);
9665  } else {
9666  ast_str_append(&out, 0, "unlimited");
9667  }
9668  sl = 0;
9669  sl2 = 0;
9670  if (q->callscompleted > 0) {
9671  sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
9672  }
9673  if (q->callscompleted + q->callsabandoned > 0) {
9674  sl2 =100 * (((float)q->callsabandonedinsl + (float)q->callscompletedinsl) / ((float)q->callsabandoned + (float)q->callscompleted));
9675  }
9676 
9677  ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime, %ds talktime), W:%d, C:%d, A:%d, SL:%2.1f%%, SL2:%2.1f%% within %ds",
9678  int2strat(q->strategy), q->holdtime, q->talktime, q->weight, q->callscompleted, q->callsabandoned, sl, sl2, q->servicelevel);
9679  do_print(s, fd, ast_str_buffer(out));
9680  if (!ao2_container_count(q->members)) {
9681  do_print(s, fd, " No Members");
9682  } else {
9683  struct member *mem;
9684 
9685  do_print(s, fd, " Members: ");
9686  mem_iter = ao2_iterator_init(q->members, 0);
9687  while ((mem = ao2_iterator_next(&mem_iter))) {
9688  ast_str_set(&out, 0, " %s", mem->membername);
9689  if (strcasecmp(mem->membername, mem->interface)) {
9690  ast_str_append(&out, 0, " (%s", mem->interface);
9691  if (!ast_strlen_zero(mem->state_interface)
9692  && strcmp(mem->state_interface, mem->interface)) {
9693  ast_str_append(&out, 0, " from %s", mem->state_interface);
9694  }
9695  ast_str_append(&out, 0, ")");
9696  }
9697  if (mem->penalty) {
9698  ast_str_append(&out, 0, " with penalty %d", mem->penalty);
9699  }
9700 
9701  ast_str_append(&out, 0, " (ringinuse %s)", mem->ringinuse ? "enabled" : "disabled");
9702 
9703  ast_str_append(&out, 0, "%s%s%s%s%s%s%s%s%s",
9704  mem->dynamic ? ast_term_color(COLOR_CYAN, COLOR_BLACK) : "", mem->dynamic ? " (dynamic)" : "", ast_term_reset(),
9705  mem->realtime ? ast_term_color(COLOR_MAGENTA, COLOR_BLACK) : "", mem->realtime ? " (realtime)" : "", ast_term_reset(),
9706  mem->starttime ? ast_term_color(COLOR_BROWN, COLOR_BLACK) : "", mem->starttime ? " (in call)" : "", ast_term_reset());
9707 
9708  if (mem->paused) {
9709  ast_str_append(&out, 0, " %s(paused%s%s was %ld secs ago)%s",
9711  ast_strlen_zero(mem->reason_paused) ? "" : ":",
9712  ast_strlen_zero(mem->reason_paused) ? "" : mem->reason_paused,
9713  (long) (now - mem->lastpause),
9714  ast_term_reset());
9715  }
9716 
9717  ast_str_append(&out, 0, " (%s%s%s)",
9722  if (mem->calls) {
9723  ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)",
9724  mem->calls, (long) (now - mem->lastcall));
9725  } else {
9726  ast_str_append(&out, 0, " has taken no calls yet");
9727  }
9728  do_print(s, fd, ast_str_buffer(out));
9729  ao2_ref(mem, -1);
9730  }
9731  ao2_iterator_destroy(&mem_iter);
9732  }
9733  if (!q->head) {
9734  do_print(s, fd, " No Callers");
9735  } else {
9736  struct queue_ent *qe;
9737  int pos = 1;
9738 
9739  do_print(s, fd, " Callers: ");
9740  for (qe = q->head; qe; qe = qe->next) {
9741  ast_str_set(&out, 0, " %d. %s (wait: %ld:%2.2ld, prio: %d)",
9742  pos++, ast_channel_name(qe->chan), (long) (now - qe->start) / 60,
9743  (long) (now - qe->start) % 60, qe->prio);
9744  do_print(s, fd, ast_str_buffer(out));
9745  }
9746  }
9747  do_print(s, fd, ""); /* blank line between entries */
9748 }
9749 
9751 
9752 /*!
9753  * \brief Show queue(s) status and statistics
9754  *
9755  * List the queues strategy, calls processed, members logged in,
9756  * other queue statistics such as avg hold time.
9757 */
9758 static char *__queues_show(struct mansession *s, int fd, int argc, const char * const *argv)
9759 {
9760  struct call_queue *q;
9761  struct ast_str *out = ast_str_alloca(512);
9762  struct ao2_container *sorted_queues;
9763 
9764  struct ao2_iterator queue_iter;
9765  int found = 0;
9766 
9767  if (argc != 2 && argc != 3) {
9768  return CLI_SHOWUSAGE;
9769  }
9770 
9771  if (argc == 3) { /* specific queue */
9772  if ((q = find_load_queue_rt_friendly(argv[2]))) {
9773  ao2_lock(q);
9774  print_queue(s, fd, q);
9775  ao2_unlock(q);
9776  queue_unref(q);
9777  } else {
9778  ast_str_set(&out, 0, "No such queue: %s.", argv[2]);
9779  do_print(s, fd, ast_str_buffer(out));
9780  }
9781  return CLI_SUCCESS;
9782  }
9783 
9784  if (ast_check_realtime("queues")) {
9785  /* This block is to find any queues which are defined in realtime but
9786  * which have not yet been added to the in-core container
9787  */
9788  struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
9789  if (cfg) {
9790  char *category = NULL;
9791  while ((category = ast_category_browse(cfg, category))) {
9792  const char *queuename = ast_variable_retrieve(cfg, category, "name");
9793  if (ast_strlen_zero(queuename)) {
9794  ast_log(LOG_WARNING, "Ignoring realtime queue with a NULL or empty 'name.'\n");
9795  continue;
9796  }
9797  if ((q = find_load_queue_rt_friendly(queuename))) {
9798  queue_t_unref(q, "Done with temporary pointer");
9799  }
9800  }
9801  ast_config_destroy(cfg);
9802  }
9803  }
9804 
9805  /*
9806  * Snapping a copy of the container prevents having to lock both the queues container
9807  * and the queue itself at the same time. It also allows us to sort the entries.
9808  */
9809  sorted_queues = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, call_queue_sort_fn, NULL);
9810  if (!sorted_queues) {
9811  return CLI_SUCCESS;
9812  }
9813  if (ao2_container_dup(sorted_queues, queues, 0)) {
9814  ao2_ref(sorted_queues, -1);
9815  return CLI_SUCCESS;
9816  }
9817 
9818  /*
9819  * No need to lock the container since it's temporary and static.
9820  * We also unlink the entries as we use them so the container is
9821  * empty when the iterator finishes. We can then just unref the container.
9822  */
9823  queue_iter = ao2_iterator_init(sorted_queues, AO2_ITERATOR_DONTLOCK | AO2_ITERATOR_UNLINK);
9824  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
9825  struct call_queue *realtime_queue = NULL;
9826  ao2_lock(q);
9827  /* This check is to make sure we don't print information for realtime
9828  * queues which have been deleted from realtime but which have not yet
9829  * been deleted from the in-core container. Only do this if we're not
9830  * looking for a specific queue.
9831  */
9832  if (q->realtime) {
9833  realtime_queue = find_load_queue_rt_friendly(q->name);
9834  if (!realtime_queue) {
9835  ao2_unlock(q);
9836  queue_t_unref(q, "Done with iterator");
9837  continue;
9838  }
9839  queue_t_unref(realtime_queue, "Queue is already in memory");
9840  }
9841 
9842  found = 1;
9843  print_queue(s, fd, q);
9844 
9845  ao2_unlock(q);
9846  queue_t_unref(q, "Done with iterator"); /* Unref the iterator's reference */
9847  }
9848  ao2_iterator_destroy(&queue_iter);
9849  ao2_ref(sorted_queues, -1);
9850  if (!found) {
9851  ast_str_set(&out, 0, "No queues.");
9852  do_print(s, fd, ast_str_buffer(out));
9853  }
9854  return CLI_SUCCESS;
9855 }
9856 
9857 /*!
9858  * \brief Check if a given word is in a space-delimited list
9859  *
9860  * \param list Space delimited list of words
9861  * \param word The word used to search the list
9862  *
9863  * \note This function will not return 1 if the word is at the very end of the
9864  * list (followed immediately by a \0, not a space) since it is used for
9865  * checking tab-completion and a word at the end is still being tab-completed.
9866  *
9867  * \return Returns 1 if the word is found
9868  * \return Returns 0 if the word is not found
9869 */
9870 static int word_in_list(const char *list, const char *word) {
9871  int list_len, word_len = strlen(word);
9872  const char *find, *end_find, *end_list;
9873 
9874  /* strip whitespace from front */
9875  while(isspace(*list)) {
9876  list++;
9877  }
9878 
9879  while((find = strstr(list, word))) {
9880  /* beginning of find starts inside another word? */
9881  if (find != list && *(find - 1) != ' ') {
9882  list = find;
9883  /* strip word from front */
9884  while(!isspace(*list) && *list != '\0') {
9885  list++;
9886  }
9887  /* strip whitespace from front */
9888  while(isspace(*list)) {
9889  list++;
9890  }
9891  continue;
9892  }
9893 
9894  /* end of find ends inside another word or at very end of list? */
9895  list_len = strlen(list);
9896  end_find = find + word_len;
9897  end_list = list + list_len;
9898  if (end_find == end_list || *end_find != ' ') {
9899  list = find;
9900  /* strip word from front */
9901  while(!isspace(*list) && *list != '\0') {
9902  list++;
9903  }
9904  /* strip whitespace from front */
9905  while(isspace(*list)) {
9906  list++;
9907  }
9908  continue;
9909  }
9910 
9911  /* terminating conditions satisfied, word at beginning or separated by ' ' */
9912  return 1;
9913  }
9914 
9915  return 0;
9916 }
9917 
9918 /*!
9919  * \brief Check if a given word is in a space-delimited list
9920  *
9921  * \param line The line as typed not including the current word being completed
9922  * \param word The word currently being completed
9923  * \param pos The number of completed words in line
9924  * \param state The nth desired completion option
9925  * \param word_list_offset Offset into the line where the list of queues begins. If non-zero, queues in the list will not be offered for further completion.
9926  *
9927  * \return Returns the queue tab-completion for the given word and state
9928 */
9929 static char *complete_queue(const char *line, const char *word, int pos, int state, ptrdiff_t word_list_offset)
9930 {
9931  struct call_queue *q;
9932  char *ret = NULL;
9933  int which = 0;
9934  int wordlen = strlen(word);
9935  struct ao2_iterator queue_iter;
9936  const char *word_list = NULL;
9937 
9938  /* for certain commands, already completed items should be left out of
9939  * the list */
9940  if (word_list_offset && strlen(line) >= word_list_offset) {
9941  word_list = line + word_list_offset;
9942  }
9943 
9944  queue_iter = ao2_iterator_init(queues, 0);
9945  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
9946  if (!strncasecmp(word, q->name, wordlen) && ++which > state
9947  && (!word_list_offset || !word_in_list(word_list, q->name))) {
9948  ret = ast_strdup(q->name);
9949  queue_t_unref(q, "Done with iterator");
9950  break;
9951  }
9952  queue_t_unref(q, "Done with iterator");
9953  }
9954  ao2_iterator_destroy(&queue_iter);
9955 
9956  /* Pretend "rules" is at the end of the queues list in certain
9957  * circumstances since it is an alternate command that should be
9958  * tab-completable for "queue show" */
9959  if (!ret && which == state && !wordlen && !strncmp("queue show", line, 10)) {
9960  ret = ast_strdup("rules");
9961  }
9962 
9963  return ret;
9964 }
9965 
9966 static char *complete_queue_show(const char *line, const char *word, int pos, int state)
9967 {
9968  if (pos == 2) {
9969  return complete_queue(line, word, pos, state, 0);
9970  }
9971  return NULL;
9972 }
9973 
9974 static char *queue_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
9975 {
9976  switch ( cmd ) {
9977  case CLI_INIT:
9978  e->command = "queue show";
9979  e->usage =
9980  "Usage: queue show\n"
9981  " Provides summary information on a specified queue.\n";
9982  return NULL;
9983  case CLI_GENERATE:
9984  return complete_queue_show(a->line, a->word, a->pos, a->n);
9985  }
9986 
9987  return __queues_show(NULL, a->fd, a->argc, a->argv);
9988 }
9989 
9990 static int manager_queue_rule_show(struct mansession *s, const struct message *m)
9991 {
9992  const char *rule = astman_get_header(m, "Rule");
9993  const char *id = astman_get_header(m, "ActionID");
9994  struct rule_list *rl_iter;
9995  struct penalty_rule *pr_iter;
9996 
9997  astman_append(s, "Response: Success\r\n");
9998  if (!ast_strlen_zero(id)) {
9999  astman_append(s, "ActionID: %s\r\n", id);
10000  }
10001 
10003  AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
10004  if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) {
10005  astman_append(s, "RuleList: %s\r\n", rl_iter->name);
10006  AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
10007  astman_append(s, "Rule: %d,%s%d,%s%d\r\n", pr_iter->time, pr_iter->max_relative && pr_iter->max_value >= 0 ? "+" : "", pr_iter->max_value, pr_iter->min_relative && pr_iter->min_value >= 0 ? "+" : "", pr_iter->min_value );
10008  }
10009  if (!ast_strlen_zero(rule)) {
10010  break;
10011  }
10012  }
10013  }
10015 
10016  /*
10017  * Two blank lines instead of one because the Response and
10018  * ActionID headers used to not be present.
10019  */
10020  astman_append(s, "\r\n\r\n");
10021 
10022  return RESULT_SUCCESS;
10023 }
10024 
10025 /*! \brief Summary of queue info via the AMI */
10026 static int manager_queues_summary(struct mansession *s, const struct message *m)
10027 {
10028  time_t now;
10029  int qmemcount = 0;
10030  int qmemavail = 0;
10031  int qchancount = 0;
10032  int qlongestholdtime = 0;
10033  int qsummaries = 0;
10034  const char *id = astman_get_header(m, "ActionID");
10035  const char *queuefilter = astman_get_header(m, "Queue");
10036  char idText[256];
10037  struct call_queue *q;
10038  struct queue_ent *qe;
10039  struct member *mem;
10040  struct ao2_iterator queue_iter;
10041  struct ao2_iterator mem_iter;
10042 
10043  astman_send_listack(s, m, "Queue summary will follow", "start");
10044  time(&now);
10045  idText[0] = '\0';
10046  if (!ast_strlen_zero(id)) {
10047  snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
10048  }
10049  queue_iter = ao2_iterator_init(queues, 0);
10050  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10051  ao2_lock(q);
10052 
10053  /* List queue properties */
10054  if (ast_strlen_zero(queuefilter) || !strcasecmp(q->name, queuefilter)) {
10055  /* Reset the necessary local variables if no queuefilter is set*/
10056  qmemcount = 0;
10057  qmemavail = 0;
10058  qchancount = 0;
10059  qlongestholdtime = 0;
10060 
10061  /* List Queue Members */
10062  mem_iter = ao2_iterator_init(q->members, 0);
10063  while ((mem = ao2_iterator_next(&mem_iter))) {
10064  if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) {
10065  ++qmemcount;
10066  if (member_status_available(mem->status) && !mem->paused) {
10067  ++qmemavail;
10068  }
10069  }
10070  ao2_ref(mem, -1);
10071  }
10072  ao2_iterator_destroy(&mem_iter);
10073  for (qe = q->head; qe; qe = qe->next) {
10074  if ((now - qe->start) > qlongestholdtime) {
10075  qlongestholdtime = now - qe->start;
10076  }
10077  ++qchancount;
10078  }
10079  astman_append(s, "Event: QueueSummary\r\n"
10080  "Queue: %s\r\n"
10081  "LoggedIn: %d\r\n"
10082  "Available: %d\r\n"
10083  "Callers: %d\r\n"
10084  "HoldTime: %d\r\n"
10085  "TalkTime: %d\r\n"
10086  "LongestHoldTime: %d\r\n"
10087  "%s"
10088  "\r\n",
10089  q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText);
10090  ++qsummaries;
10091  }
10092  ao2_unlock(q);
10093  queue_t_unref(q, "Done with iterator");
10094  }
10095  ao2_iterator_destroy(&queue_iter);
10096 
10097  astman_send_list_complete_start(s, m, "QueueSummaryComplete", qsummaries);
10099 
10100  return RESULT_SUCCESS;
10101 }
10102 
10103 /*! \brief Queue status info via AMI */
10104 static int manager_queues_status(struct mansession *s, const struct message *m)
10105 {
10106  time_t now;
10107  int pos;
10108  int q_items = 0;
10109  const char *id = astman_get_header(m,"ActionID");
10110  const char *queuefilter = astman_get_header(m,"Queue");
10111  const char *memberfilter = astman_get_header(m,"Member");
10112  char idText[256];
10113  struct call_queue *q;
10114  struct queue_ent *qe;
10115  float sl = 0;
10116  float sl2 = 0;
10117  struct member *mem;
10118  struct ao2_iterator queue_iter;
10119  struct ao2_iterator mem_iter;
10120 
10121  astman_send_listack(s, m, "Queue status will follow", "start");
10122  time(&now);
10123  idText[0] = '\0';
10124  if (!ast_strlen_zero(id)) {
10125  snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
10126  }
10127 
10128  queue_iter = ao2_iterator_init(queues, 0);
10129  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10130  ao2_lock(q);
10131 
10132  /* List queue properties */
10133  if (ast_strlen_zero(queuefilter) || !strcasecmp(q->name, queuefilter)) {
10134  sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0);
10135  sl2 = (((q->callscompleted + q->callsabandoned) > 0) ? 100 * (((float)q->callsabandonedinsl + (float)q->callscompletedinsl) / ((float)q->callsabandoned + (float)q->callscompleted)) : 0);
10136 
10137  astman_append(s, "Event: QueueParams\r\n"
10138  "Queue: %s\r\n"
10139  "Max: %d\r\n"
10140  "Strategy: %s\r\n"
10141  "Calls: %d\r\n"
10142  "Holdtime: %d\r\n"
10143  "TalkTime: %d\r\n"
10144  "Completed: %d\r\n"
10145  "Abandoned: %d\r\n"
10146  "ServiceLevel: %d\r\n"
10147  "ServicelevelPerf: %2.1f\r\n"
10148  "ServicelevelPerf2: %2.1f\r\n"
10149  "Weight: %d\r\n"
10150  "%s"
10151  "\r\n",
10152  q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted,
10153  q->callsabandoned, q->servicelevel, sl, sl2, q->weight, idText);
10154  ++q_items;
10155 
10156  /* List Queue Members */
10157  mem_iter = ao2_iterator_init(q->members, 0);
10158  while ((mem = ao2_iterator_next(&mem_iter))) {
10159  if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) {
10160  astman_append(s, "Event: QueueMember\r\n"
10161  "Queue: %s\r\n"
10162  "Name: %s\r\n"
10163  "Location: %s\r\n"
10164  "StateInterface: %s\r\n"
10165  "Membership: %s\r\n"
10166  "Penalty: %d\r\n"
10167  "CallsTaken: %d\r\n"
10168  "LastCall: %d\r\n"
10169  "LastPause: %d\r\n"
10170  "InCall: %d\r\n"
10171  "Status: %d\r\n"
10172  "Paused: %d\r\n"
10173  "PausedReason: %s\r\n"
10174  "Wrapuptime: %d\r\n"
10175  "%s"
10176  "\r\n",
10177  q->name, mem->membername, mem->interface, mem->state_interface, mem->dynamic ? "dynamic" : "static",
10178  mem->penalty, mem->calls, (int)mem->lastcall, (int)mem->lastpause, mem->starttime ? 1 : 0, mem->status,
10179  mem->paused, mem->reason_paused, mem->wrapuptime, idText);
10180  ++q_items;
10181  }
10182  ao2_ref(mem, -1);
10183  }
10184  ao2_iterator_destroy(&mem_iter);
10185 
10186  /* List Queue Entries */
10187  pos = 1;
10188  for (qe = q->head; qe; qe = qe->next) {
10189  astman_append(s, "Event: QueueEntry\r\n"
10190  "Queue: %s\r\n"
10191  "Position: %d\r\n"
10192  "Channel: %s\r\n"
10193  "Uniqueid: %s\r\n"
10194  "CallerIDNum: %s\r\n"
10195  "CallerIDName: %s\r\n"
10196  "ConnectedLineNum: %s\r\n"
10197  "ConnectedLineName: %s\r\n"
10198  "Wait: %ld\r\n"
10199  "Priority: %d\r\n"
10200  "%s"
10201  "\r\n",
10202  q->name, pos++, ast_channel_name(qe->chan), ast_channel_uniqueid(qe->chan),
10207  (long) (now - qe->start), qe->prio, idText);
10208  ++q_items;
10209  }
10210  }
10211  ao2_unlock(q);
10212  queue_t_unref(q, "Done with iterator");
10213  }
10214  ao2_iterator_destroy(&queue_iter);
10215 
10216  astman_send_list_complete_start(s, m, "QueueStatusComplete", q_items);
10218 
10219  return RESULT_SUCCESS;
10220 }
10221 
10222 static int manager_add_queue_member(struct mansession *s, const struct message *m)
10223 {
10224  const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface, *wrapuptime_s;
10225  int paused, penalty, wrapuptime = 0;
10226 
10227  queuename = astman_get_header(m, "Queue");
10228  interface = astman_get_header(m, "Interface");
10229  penalty_s = astman_get_header(m, "Penalty");
10230  paused_s = astman_get_header(m, "Paused");
10231  membername = astman_get_header(m, "MemberName");
10232  state_interface = astman_get_header(m, "StateInterface");
10233  wrapuptime_s = astman_get_header(m, "Wrapuptime");
10234 
10235  if (ast_strlen_zero(queuename)) {
10236  astman_send_error(s, m, "'Queue' not specified.");
10237  return 0;
10238  }
10239 
10240  if (ast_strlen_zero(interface)) {
10241  astman_send_error(s, m, "'Interface' not specified.");
10242  return 0;
10243  }
10244 
10245  if (ast_strlen_zero(penalty_s)) {
10246  penalty = 0;
10247  } else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0) {
10248  penalty = 0;
10249  }
10250 
10251  if (ast_strlen_zero(wrapuptime_s)) {
10252  wrapuptime = 0;
10253  } else if (sscanf(wrapuptime_s, "%30d", &wrapuptime) != 1 || wrapuptime < 0) {
10254  wrapuptime = 0;
10255  }
10256 
10257  if (ast_strlen_zero(paused_s)) {
10258  paused = 0;
10259  } else {
10260  paused = abs(ast_true(paused_s));
10261  }
10262 
10263  switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface, NULL, wrapuptime)) {
10264  case RES_OKAY:
10265  if (ast_strlen_zero(membername) || !log_membername_as_agent) {
10266  ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
10267  } else {
10268  ast_queue_log(queuename, "MANAGER", membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
10269  }
10270  astman_send_ack(s, m, "Added interface to queue");
10271  break;
10272  case RES_EXISTS:
10273  astman_send_error(s, m, "Unable to add interface: Already there");
10274  break;
10275  case RES_NOSUCHQUEUE:
10276  astman_send_error(s, m, "Unable to add interface to queue: No such queue");
10277  break;
10278  case RES_OUTOFMEMORY:
10279  astman_send_error(s, m, "Out of memory");
10280  break;
10281  }
10282 
10283  return 0;
10284 }
10285 
10286 static int manager_remove_queue_member(struct mansession *s, const struct message *m)
10287 {
10288  const char *queuename, *interface;
10289  struct member *mem = NULL;
10290 
10291  queuename = astman_get_header(m, "Queue");
10292  interface = astman_get_header(m, "Interface");
10293 
10294  if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
10295  astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
10296  return 0;
10297  }
10298 
10299  if (log_membername_as_agent) {
10300  mem = find_member_by_queuename_and_interface(queuename, interface);
10301  }
10302 
10303  switch (remove_from_queue(queuename, interface)) {
10304  case RES_OKAY:
10305  if (!mem || ast_strlen_zero(mem->membername)) {
10306  ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
10307  } else {
10308  ast_queue_log(queuename, "MANAGER", mem->membername, "REMOVEMEMBER", "%s", "");
10309  }
10310  astman_send_ack(s, m, "Removed interface from queue");
10311  break;
10312  case RES_EXISTS:
10313  astman_send_error(s, m, "Unable to remove interface: Not there");
10314  break;
10315  case RES_NOSUCHQUEUE:
10316  astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
10317  break;
10318  case RES_OUTOFMEMORY:
10319  astman_send_error(s, m, "Out of memory");
10320  break;
10321  case RES_NOT_DYNAMIC:
10322  astman_send_error(s, m, "Member not dynamic");
10323  break;
10324  }
10325 
10326  if (mem) {
10327  ao2_ref(mem, -1);
10328  }
10329 
10330  return 0;
10331 }
10332 
10333 static int manager_pause_queue_member(struct mansession *s, const struct message *m)
10334 {
10335  const char *queuename, *interface, *paused_s, *reason;
10336  int paused;
10337 
10338  interface = astman_get_header(m, "Interface");
10339  paused_s = astman_get_header(m, "Paused");
10340  queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */
10341  reason = astman_get_header(m, "Reason"); /* Optional */
10342 
10343  if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
10344  astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
10345  return 0;
10346  }
10347 
10348  paused = abs(ast_true(paused_s));
10349 
10350  if (set_member_paused(queuename, interface, reason, paused)) {
10351  astman_send_error(s, m, "Interface not found");
10352  } else {
10353  astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
10354  }
10355  return 0;
10356 }
10357 
10358 static int manager_queue_log_custom(struct mansession *s, const struct message *m)
10359 {
10360  const char *queuename, *event, *message, *interface, *uniqueid;
10361 
10362  queuename = astman_get_header(m, "Queue");
10363  uniqueid = astman_get_header(m, "UniqueId");
10364  interface = astman_get_header(m, "Interface");
10365  event = astman_get_header(m, "Event");
10366  message = astman_get_header(m, "Message");
10367 
10368  if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) {
10369  astman_send_error(s, m, "Need 'Queue' and 'Event' parameters.");
10370  return 0;
10371  }
10372 
10373  ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message);
10374  astman_send_ack(s, m, "Event added successfully");
10375 
10376  return 0;
10377 }
10378 
10379 static int manager_queue_reload(struct mansession *s, const struct message *m)
10380 {
10381  struct ast_flags mask = {0,};
10382  const char *queuename = NULL;
10383  int header_found = 0;
10384 
10385  queuename = astman_get_header(m, "Queue");
10386  if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) {
10388  header_found = 1;
10389  }
10390  if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) {
10392  header_found = 1;
10393  }
10394  if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) {
10396  header_found = 1;
10397  }
10398 
10399  if (!header_found) {
10400  ast_set_flag(&mask, AST_FLAGS_ALL);
10401  }
10402 
10403  if (!reload_handler(1, &mask, queuename)) {
10404  astman_send_ack(s, m, "Queue reloaded successfully");
10405  } else {
10406  astman_send_error(s, m, "Error encountered while reloading queue");
10407  }
10408  return 0;
10409 }
10410 
10411 static int manager_queue_reset(struct mansession *s, const struct message *m)
10412 {
10413  const char *queuename = NULL;
10414  struct ast_flags mask = {QUEUE_RESET_STATS,};
10415 
10416  queuename = astman_get_header(m, "Queue");
10417 
10418  if (!reload_handler(1, &mask, queuename)) {
10419  astman_send_ack(s, m, "Queue stats reset successfully");
10420  } else {
10421  astman_send_error(s, m, "Error encountered while resetting queue stats");
10422  }
10423  return 0;
10424 }
10425 
10426 static char *complete_queue_add_member(const char *line, const char *word, int pos, int state)
10427 {
10428  /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
10429  switch (pos) {
10430  case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
10431  return NULL;
10432  case 4: /* only one possible match, "to" */
10433  return state == 0 ? ast_strdup("to") : NULL;
10434  case 5: /* <queue> */
10435  return complete_queue(line, word, pos, state, 0);
10436  case 6: /* only one possible match, "penalty" */
10437  return state == 0 ? ast_strdup("penalty") : NULL;
10438  case 7:
10439  if (0 <= state && state < 100) { /* 0-99 */
10440  char *num;
10441  if ((num = ast_malloc(3))) {
10442  sprintf(num, "%d", state);
10443  }
10444  return num;
10445  } else {
10446  return NULL;
10447  }
10448  case 8: /* only one possible match, "as" */
10449  return state == 0 ? ast_strdup("as") : NULL;
10450  case 9: /* Don't attempt to complete name of member (infinite possibilities) */
10451  return NULL;
10452  default:
10453  return NULL;
10454  }
10455 }
10456 
10457 static int manager_queue_member_ringinuse(struct mansession *s, const struct message *m)
10458 {
10459  const char *queuename, *interface, *ringinuse_s;
10460  int ringinuse;
10461 
10462  interface = astman_get_header(m, "Interface");
10463  ringinuse_s = astman_get_header(m, "RingInUse");
10464 
10465  /* Optional - if not supplied, set the ringinuse value for the given Interface in all queues */
10466  queuename = astman_get_header(m, "Queue");
10467 
10468  if (ast_strlen_zero(interface) || ast_strlen_zero(ringinuse_s)) {
10469  astman_send_error(s, m, "Need 'Interface' and 'RingInUse' parameters.");
10470  return 0;
10471  }
10472 
10473  if (ast_true(ringinuse_s)) {
10474  ringinuse = 1;
10475  } else if (ast_false(ringinuse_s)) {
10476  ringinuse = 0;
10477  } else {
10478  astman_send_error(s, m, "'RingInUse' parameter must be a truth value (yes/no, on/off, 0/1, etc)");
10479  return 0;
10480  }
10481 
10482  if (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
10483  astman_send_error(s, m, "Invalid interface, queuename, or ringinuse value\n");
10484  } else {
10485  astman_send_ack(s, m, "Interface ringinuse set successfully");
10486  }
10487 
10488  return 0;
10489 }
10490 
10491 static int manager_queue_member_penalty(struct mansession *s, const struct message *m)
10492 {
10493  const char *queuename, *interface, *penalty_s;
10494  int penalty;
10495 
10496  interface = astman_get_header(m, "Interface");
10497  penalty_s = astman_get_header(m, "Penalty");
10498  /* Optional - if not supplied, set the penalty value for the given Interface in all queues */
10499  queuename = astman_get_header(m, "Queue");
10500 
10501  if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) {
10502  astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters.");
10503  return 0;
10504  }
10505 
10506  penalty = atoi(penalty_s);
10507 
10508  if (set_member_value((char *)queuename, (char *)interface, MEMBER_PENALTY, penalty)) {
10509  astman_send_error(s, m, "Invalid interface, queuename or penalty");
10510  } else {
10511  astman_send_ack(s, m, "Interface penalty set successfully");
10512  }
10513 
10514  return 0;
10515 }
10516 
10517 static int manager_change_priority_caller_on_queue(struct mansession *s, const struct message *m)
10518 {
10519  const char *queuename, *caller, *priority_s;
10520  int priority = 0;
10521 
10522  queuename = astman_get_header(m, "Queue");
10523  caller = astman_get_header(m, "Caller");
10524  priority_s = astman_get_header(m, "Priority");
10525 
10526  if (ast_strlen_zero(queuename)) {
10527  astman_send_error(s, m, "'Queue' not specified.");
10528  return 0;
10529  }
10530 
10531  if (ast_strlen_zero(caller)) {
10532  astman_send_error(s, m, "'Caller' not specified.");
10533  return 0;
10534  }
10535 
10536  if (ast_strlen_zero(priority_s)) {
10537  astman_send_error(s, m, "'Priority' not specified.");
10538  return 0;
10539  } else if (sscanf(priority_s, "%30d", &priority) != 1) {
10540  astman_send_error(s, m, "'Priority' need integer.");
10541  return 0;
10542  }
10543 
10544  switch (change_priority_caller_on_queue(queuename, caller, priority)) {
10545  case RES_OKAY:
10546  astman_send_ack(s, m, "Priority change for caller on queue");
10547  break;
10548  case RES_NOSUCHQUEUE:
10549  astman_send_error(s, m, "Unable to change priority caller on queue: No such queue");
10550  break;
10551  case RES_NOT_CALLER:
10552  astman_send_error(s, m, "Unable to change priority caller on queue: No such caller");
10553  break;
10554  }
10555 
10556  return 0;
10557 }
10558 
10559 
10560 
10561 static char *handle_queue_add_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
10562 {
10563  const char *queuename, *interface, *membername = NULL, *state_interface = NULL;
10564  int penalty;
10565 
10566  switch ( cmd ) {
10567  case CLI_INIT:
10568  e->command = "queue add member";
10569  e->usage =
10570  "Usage: queue add member <dial string> to <queue> [[[penalty <penalty>] as <membername>] state_interface <interface>]\n"
10571  " Add a dial string (Such as a channel,e.g. SIP/6001) to a queue with optionally: a penalty, membername and a state_interface\n";
10572  return NULL;
10573  case CLI_GENERATE:
10574  return complete_queue_add_member(a->line, a->word, a->pos, a->n);
10575  }
10576 
10577  if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12)) {
10578  return CLI_SHOWUSAGE;
10579  } else if (strcmp(a->argv[4], "to")) {
10580  return CLI_SHOWUSAGE;
10581  } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) {
10582  return CLI_SHOWUSAGE;
10583  } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) {
10584  return CLI_SHOWUSAGE;
10585  } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) {
10586  return CLI_SHOWUSAGE;
10587  }
10588 
10589  queuename = a->argv[5];
10590  interface = a->argv[3];
10591  if (a->argc >= 8) {
10592  if (sscanf(a->argv[7], "%30d", &penalty) == 1) {
10593  if (penalty < 0) {
10594  ast_cli(a->fd, "Penalty must be >= 0\n");
10595  penalty = 0;
10596  }
10597  } else {
10598  ast_cli(a->fd, "Penalty must be an integer >= 0\n");
10599  penalty = 0;
10600  }
10601  } else {
10602  penalty = 0;
10603  }
10604 
10605  if (a->argc >= 10) {
10606  membername = a->argv[9];
10607  }
10608 
10609  if (a->argc >= 12) {
10610  state_interface = a->argv[11];
10611  }
10612 
10613  switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface, NULL, 0)) {
10614  case RES_OKAY:
10615  if (ast_strlen_zero(membername) || !log_membername_as_agent) {
10616  ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
10617  } else {
10618  ast_queue_log(queuename, "CLI", membername, "ADDMEMBER", "%s", "");
10619  }
10620  ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
10621  return CLI_SUCCESS;
10622  case RES_EXISTS:
10623  ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
10624  return CLI_FAILURE;
10625  case RES_NOSUCHQUEUE:
10626  ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
10627  return CLI_FAILURE;
10628  case RES_OUTOFMEMORY:
10629  ast_cli(a->fd, "Out of memory\n");
10630  return CLI_FAILURE;
10631  case RES_NOT_DYNAMIC:
10632  ast_cli(a->fd, "Member not dynamic\n");
10633  return CLI_FAILURE;
10634  default:
10635  return CLI_FAILURE;
10636  }
10637 }
10638 
10639 static char *complete_queue_remove_member(const char *line, const char *word, int pos, int state)
10640 {
10641  int which = 0;
10642  struct call_queue *q;
10643  struct member *m;
10644  struct ao2_iterator queue_iter;
10645  struct ao2_iterator mem_iter;
10646  int wordlen = strlen(word);
10647 
10648  /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
10649  if (pos > 5 || pos < 3) {
10650  return NULL;
10651  }
10652  if (pos == 4) { /* only one possible match, 'from' */
10653  return (state == 0 ? ast_strdup("from") : NULL);
10654  }
10655 
10656  if (pos == 5) { /* No need to duplicate code */
10657  return complete_queue(line, word, pos, state, 0);
10658  }
10659 
10660  /* here is the case for 3, <member> */
10661  queue_iter = ao2_iterator_init(queues, 0);
10662  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10663  ao2_lock(q);
10664  mem_iter = ao2_iterator_init(q->members, 0);
10665  while ((m = ao2_iterator_next(&mem_iter))) {
10666  if (!strncasecmp(word, m->membername, wordlen) && ++which > state) {
10667  char *tmp;
10668  tmp = ast_strdup(m->interface);
10669  ao2_ref(m, -1);
10670  ao2_iterator_destroy(&mem_iter);
10671  ao2_unlock(q);
10672  queue_t_unref(q, "Done with iterator, returning interface name");
10673  ao2_iterator_destroy(&queue_iter);
10674  return tmp;
10675  }
10676  ao2_ref(m, -1);
10677  }
10678  ao2_iterator_destroy(&mem_iter);
10679  ao2_unlock(q);
10680  queue_t_unref(q, "Done with iterator");
10681  }
10682  ao2_iterator_destroy(&queue_iter);
10683 
10684  return NULL;
10685 }
10686 
10687 static char *handle_queue_remove_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
10688 {
10689  const char *queuename, *interface;
10690  struct member *mem = NULL;
10691  char *res = CLI_FAILURE;
10692 
10693  switch (cmd) {
10694  case CLI_INIT:
10695  e->command = "queue remove member";
10696  e->usage =
10697  "Usage: queue remove member <channel> from <queue>\n"
10698  " Remove a specific channel from a queue.\n";
10699  return NULL;
10700  case CLI_GENERATE:
10701  return complete_queue_remove_member(a->line, a->word, a->pos, a->n);
10702  }
10703 
10704  if (a->argc != 6) {
10705  return CLI_SHOWUSAGE;
10706  } else if (strcmp(a->argv[4], "from")) {
10707  return CLI_SHOWUSAGE;
10708  }
10709 
10710  queuename = a->argv[5];
10711  interface = a->argv[3];
10712 
10713  if (log_membername_as_agent) {
10714  mem = find_member_by_queuename_and_interface(queuename, interface);
10715  }
10716 
10717  switch (remove_from_queue(queuename, interface)) {
10718  case RES_OKAY:
10719  if (!mem || ast_strlen_zero(mem->membername)) {
10720  ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
10721  } else {
10722  ast_queue_log(queuename, "CLI", mem->membername, "REMOVEMEMBER", "%s", "");
10723  }
10724  ast_cli(a->fd, "Removed interface %s from queue '%s'\n", interface, queuename);
10725  res = CLI_SUCCESS;
10726  break;
10727  case RES_EXISTS:
10728  ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
10729  break;
10730  case RES_NOSUCHQUEUE:
10731  ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
10732  break;
10733  case RES_OUTOFMEMORY:
10734  ast_cli(a->fd, "Out of memory\n");
10735  break;
10736  case RES_NOT_DYNAMIC:
10737  ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Member is not dynamic\n", interface, queuename);
10738  break;
10739  }
10740 
10741  if (mem) {
10742  ao2_ref(mem, -1);
10743  }
10744 
10745  return res;
10746 }
10747 
10748 
10749 
10750 static char *handle_queue_change_priority_caller(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
10751 {
10752  const char *queuename, *caller;
10753  int priority;
10754  char *res = CLI_FAILURE;
10755 
10756  switch (cmd) {
10757  case CLI_INIT:
10758  e->command = "queue priority caller";
10759  e->usage =
10760  "Usage: queue priority caller <channel> on <queue> to <priority>\n"
10761  " Change the priority of a channel on a queue.\n";
10762  return NULL;
10763  case CLI_GENERATE:
10764  return NULL;
10765  }
10766 
10767  if (a->argc != 8) {
10768  return CLI_SHOWUSAGE;
10769  } else if (strcmp(a->argv[4], "on")) {
10770  return CLI_SHOWUSAGE;
10771  } else if (strcmp(a->argv[6], "to")) {
10772  return CLI_SHOWUSAGE;
10773  } else if (sscanf(a->argv[7], "%30d", &priority) != 1) {
10774  ast_log (LOG_ERROR, "<priority> parameter must be an integer.\n");
10775  return CLI_SHOWUSAGE;
10776  }
10777 
10778  caller = a->argv[3];
10779  queuename = a->argv[5];
10780 
10781  switch (change_priority_caller_on_queue(queuename, caller, priority)) {
10782  case RES_OKAY:
10783  res = CLI_SUCCESS;
10784  break;
10785  case RES_NOSUCHQUEUE:
10786  ast_cli(a->fd, "Unable change priority caller %s on queue '%s': No such queue\n", caller, queuename);
10787  break;
10788  case RES_NOT_CALLER:
10789  ast_cli(a->fd, "Unable to change priority caller '%s' on queue '%s': Not there\n", caller, queuename);
10790 
10791  break;
10792  }
10793 
10794  return res;
10795 }
10796 
10797 
10798 
10799 static char *complete_queue_pause_member(const char *line, const char *word, int pos, int state)
10800 {
10801  /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */
10802  switch (pos) {
10803  case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
10804  return NULL;
10805  case 4: /* only one possible match, "queue" */
10806  return state == 0 ? ast_strdup("queue") : NULL;
10807  case 5: /* <queue> */
10808  return complete_queue(line, word, pos, state, 0);
10809  case 6: /* "reason" */
10810  return state == 0 ? ast_strdup("reason") : NULL;
10811  case 7: /* Can't autocomplete a reason, since it's 100% customizeable */
10812  return NULL;
10813  default:
10814  return NULL;
10815  }
10816 }
10817 
10818 static char *handle_queue_pause_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
10819 {
10820  const char *queuename, *interface, *reason;
10821  int paused;
10822 
10823  switch (cmd) {
10824  case CLI_INIT:
10825  e->command = "queue {pause|unpause} member";
10826  e->usage =
10827  "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n"
10828  " Pause or unpause a queue member. Not specifying a particular queue\n"
10829  " will pause or unpause a member across all queues to which the member\n"
10830  " belongs.\n";
10831  return NULL;
10832  case CLI_GENERATE:
10833  return complete_queue_pause_member(a->line, a-> word, a->pos, a->n);
10834  }
10835 
10836  if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) {
10837  return CLI_SHOWUSAGE;
10838  } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) {
10839  return CLI_SHOWUSAGE;
10840  } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) {
10841  return CLI_SHOWUSAGE;
10842  }
10843 
10844 
10845  interface = a->argv[3];
10846  queuename = a->argc >= 6 ? a->argv[5] : NULL;
10847  reason = a->argc == 8 ? a->argv[7] : NULL;
10848  paused = !strcasecmp(a->argv[1], "pause");
10849 
10850  if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) {
10851  ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface);
10852  if (!ast_strlen_zero(queuename)) {
10853  ast_cli(a->fd, " in queue '%s'", queuename);
10854  }
10855  if (!ast_strlen_zero(reason)) {
10856  ast_cli(a->fd, " for reason '%s'", reason);
10857  }
10858  ast_cli(a->fd, "\n");
10859  return CLI_SUCCESS;
10860  } else {
10861  ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface);
10862  if (!ast_strlen_zero(queuename)) {
10863  ast_cli(a->fd, " in queue '%s'", queuename);
10864  }
10865  if (!ast_strlen_zero(reason)) {
10866  ast_cli(a->fd, " for reason '%s'", reason);
10867  }
10868  ast_cli(a->fd, "\n");
10869  return CLI_FAILURE;
10870  }
10871 }
10872 
10873 static char *complete_queue_set_member_value(const char *line, const char *word, int pos, int state)
10874 {
10875  /* 0 - queue; 1 - set; 2 - penalty/ringinuse; 3 - <value>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/
10876  switch (pos) {
10877  case 4:
10878  if (state == 0) {
10879  return ast_strdup("on");
10880  } else {
10881  return NULL;
10882  }
10883  case 6:
10884  if (state == 0) {
10885  return ast_strdup("in");
10886  } else {
10887  return NULL;
10888  }
10889  case 7:
10890  return complete_queue(line, word, pos, state, 0);
10891  default:
10892  return NULL;
10893  }
10894 }
10895 
10896 static char *handle_queue_set_member_ringinuse(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
10897 {
10898  const char *queuename = NULL, *interface;
10899  int ringinuse;
10900 
10901  switch (cmd) {
10902  case CLI_INIT:
10903  e->command = "queue set ringinuse";
10904  e->usage =
10905  "Usage: queue set ringinuse <yes/no> on <interface> [in <queue>]\n"
10906  " Set a member's ringinuse in the queue specified. If no queue is specified\n"
10907  " then that interface's penalty is set in all queues to which that interface is a member.\n";
10908  break;
10909  return NULL;
10910  case CLI_GENERATE:
10911  return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
10912  }
10913 
10914  /* Sensible argument counts */
10915  if (a->argc != 6 && a->argc != 8) {
10916  return CLI_SHOWUSAGE;
10917  }
10918 
10919  /* Uses proper indicational words */
10920  if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
10921  return CLI_SHOWUSAGE;
10922  }
10923 
10924  /* Set the queue name if applicale */
10925  if (a->argc == 8) {
10926  queuename = a->argv[7];
10927  }
10928 
10929  /* Interface being set */
10930  interface = a->argv[5];
10931 
10932  /* Check and set the ringinuse value */
10933  if (ast_true(a->argv[3])) {
10934  ringinuse = 1;
10935  } else if (ast_false(a->argv[3])) {
10936  ringinuse = 0;
10937  } else {
10938  return CLI_SHOWUSAGE;
10939  }
10940 
10941  switch (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
10942  case RESULT_SUCCESS:
10943  ast_cli(a->fd, "Set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
10944  return CLI_SUCCESS;
10945  case RESULT_FAILURE:
10946  ast_cli(a->fd, "Failed to set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
10947  return CLI_FAILURE;
10948  default:
10949  return CLI_FAILURE;
10950  }
10951 }
10952 
10953 static char *handle_queue_set_member_penalty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
10954 {
10955  const char *queuename = NULL, *interface;
10956  int penalty = 0;
10957 
10958  switch (cmd) {
10959  case CLI_INIT:
10960  e->command = "queue set penalty";
10961  e->usage =
10962  "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n"
10963  " Set a member's penalty in the queue specified. If no queue is specified\n"
10964  " then that interface's penalty is set in all queues to which that interface is a member\n";
10965  return NULL;
10966  case CLI_GENERATE:
10967  return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
10968  }
10969 
10970  if (a->argc != 6 && a->argc != 8) {
10971  return CLI_SHOWUSAGE;
10972  } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
10973  return CLI_SHOWUSAGE;
10974  }
10975 
10976  if (a->argc == 8) {
10977  queuename = a->argv[7];
10978  }
10979  interface = a->argv[5];
10980  penalty = atoi(a->argv[3]);
10981 
10982  switch (set_member_value(queuename, interface, MEMBER_PENALTY, penalty)) {
10983  case RESULT_SUCCESS:
10984  ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename);
10985  return CLI_SUCCESS;
10986  case RESULT_FAILURE:
10987  ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename);
10988  return CLI_FAILURE;
10989  default:
10990  return CLI_FAILURE;
10991  }
10992 }
10993 
10994 static char *complete_queue_rule_show(const char *line, const char *word, int pos, int state)
10995 {
10996  int which = 0;
10997  struct rule_list *rl_iter;
10998  int wordlen = strlen(word);
10999  char *ret = NULL;
11000  if (pos != 3) /* Wha? */ {
11001  return NULL;
11002  }
11003 
11005  AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
11006  if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) {
11007  ret = ast_strdup(rl_iter->name);
11008  break;
11009  }
11010  }
11012 
11013  return ret;
11014 }
11015 
11016 static char *handle_queue_rule_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11017 {
11018  const char *rule;
11019  struct rule_list *rl_iter;
11020  struct penalty_rule *pr_iter;
11021  switch (cmd) {
11022  case CLI_INIT:
11023  e->command = "queue show rules";
11024  e->usage =
11025  "Usage: queue show rules [rulename]\n"
11026  " Show the list of rules associated with rulename. If no\n"
11027  " rulename is specified, list all rules defined in queuerules.conf\n";
11028  return NULL;
11029  case CLI_GENERATE:
11030  return complete_queue_rule_show(a->line, a->word, a->pos, a->n);
11031  }
11032 
11033  if (a->argc != 3 && a->argc != 4) {
11034  return CLI_SHOWUSAGE;
11035  }
11036 
11037  rule = a->argc == 4 ? a->argv[3] : "";
11039  AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
11040  if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) {
11041  ast_cli(a->fd, "Rule: %s\n", rl_iter->name);
11042  AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
11043  ast_cli(a->fd, "\tAfter %d seconds, adjust QUEUE_MAX_PENALTY %s %d, adjust QUEUE_MIN_PENALTY %s %d and adjust QUEUE_RAISE_PENALTY %s %d\n", pr_iter->time, pr_iter->max_relative ? "by" : "to", pr_iter->max_value, pr_iter->min_relative ? "by" : "to", pr_iter->min_value, pr_iter->raise_relative ? "by" : "to", pr_iter->raise_value);
11044  }
11045  }
11046  }
11048  return CLI_SUCCESS;
11049 }
11050 
11051 static char *handle_queue_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11052 {
11053  struct ast_flags mask = {QUEUE_RESET_STATS,};
11054  int i;
11055 
11056  switch (cmd) {
11057  case CLI_INIT:
11058  e->command = "queue reset stats";
11059  e->usage =
11060  "Usage: queue reset stats [<queuenames>]\n"
11061  "\n"
11062  "Issuing this command will reset statistics for\n"
11063  "<queuenames>, or for all queues if no queue is\n"
11064  "specified.\n";
11065  return NULL;
11066  case CLI_GENERATE:
11067  if (a->pos >= 3) {
11068  return complete_queue(a->line, a->word, a->pos, a->n, 17);
11069  } else {
11070  return NULL;
11071  }
11072  }
11073 
11074  if (a->argc < 3) {
11075  return CLI_SHOWUSAGE;
11076  }
11077 
11078  if (a->argc == 3) {
11079  reload_handler(1, &mask, NULL);
11080  return CLI_SUCCESS;
11081  }
11082 
11083  for (i = 3; i < a->argc; ++i) {
11084  reload_handler(1, &mask, a->argv[i]);
11085  }
11086 
11087  return CLI_SUCCESS;
11088 }
11089 
11090 static char *handle_queue_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11091 {
11092  struct ast_flags mask = {0,};
11093  int i;
11094 
11095  switch (cmd) {
11096  case CLI_INIT:
11097  e->command = "queue reload {parameters|members|rules|all}";
11098  e->usage =
11099  "Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n"
11100  "Reload queues. If <queuenames> are specified, only reload information pertaining\n"
11101  "to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n"
11102  "specified in order to know what information to reload. Below is an explanation\n"
11103  "of each of these qualifiers.\n"
11104  "\n"
11105  "\t'members' - reload queue members from queues.conf\n"
11106  "\t'parameters' - reload all queue options except for queue members\n"
11107  "\t'rules' - reload the queuerules.conf file\n"
11108  "\t'all' - reload queue rules, parameters, and members\n"
11109  "\n"
11110  "Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n"
11111  "Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n"
11112  "one queue is specified when using this command, reloading queue rules may cause\n"
11113  "other queues to be affected\n";
11114  return NULL;
11115  case CLI_GENERATE:
11116  if (a->pos >= 3) {
11117  /* find the point at which the list of queue names starts */
11118  const char *command_end = a->line + strlen("queue reload ");
11119  command_end = strchr(command_end, ' ');
11120  if (!command_end) {
11121  command_end = a->line + strlen(a->line);
11122  }
11123  return complete_queue(a->line, a->word, a->pos, a->n, command_end - a->line);
11124  } else {
11125  return NULL;
11126  }
11127  }
11128 
11129  if (a->argc < 3)
11130  return CLI_SHOWUSAGE;
11131 
11132  if (!strcasecmp(a->argv[2], "rules")) {
11134  } else if (!strcasecmp(a->argv[2], "members")) {
11136  } else if (!strcasecmp(a->argv[2], "parameters")) {
11138  } else if (!strcasecmp(a->argv[2], "all")) {
11139  ast_set_flag(&mask, AST_FLAGS_ALL);
11140  }
11141 
11142  if (a->argc == 3) {
11143  reload_handler(1, &mask, NULL);
11144  return CLI_SUCCESS;
11145  }
11146 
11147  for (i = 3; i < a->argc; ++i) {
11148  reload_handler(1, &mask, a->argv[i]);
11149  }
11150 
11151  return CLI_SUCCESS;
11152 }
11153 
11154 /*!
11155  * \brief Update Queue with data of an outgoing call
11156 */
11157 static int qupd_exec(struct ast_channel *chan, const char *data)
11158 {
11159  int oldtalktime;
11160  char *parse;
11161  struct call_queue *q;
11162  struct member *mem;
11163  int newtalktime = 0;
11164 
11166  AST_APP_ARG(queuename);
11167  AST_APP_ARG(uniqueid);
11168  AST_APP_ARG(agent);
11170  AST_APP_ARG(talktime);
11171  AST_APP_ARG(params););
11172 
11173  if (ast_strlen_zero(data)) {
11174  ast_log(LOG_WARNING, "QueueUpdate requires arguments (queuename,uniqueid,agent,status,talktime,params[totaltime,callednumber])\n");
11175  return -1;
11176  }
11177 
11178  parse = ast_strdupa(data);
11179 
11180  AST_STANDARD_APP_ARGS(args, parse);
11181 
11182  if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid) || ast_strlen_zero(args.agent) || ast_strlen_zero(args.status)) {
11183  ast_log(LOG_WARNING, "Missing argument to QueueUpdate (queuename,uniqueid,agent,status,talktime,params[totaltime|callednumber])\n");
11184  return -1;
11185  }
11186 
11187  if (!ast_strlen_zero(args.talktime)) {
11188  newtalktime = atoi(args.talktime);
11189  }
11190 
11191  q = find_load_queue_rt_friendly(args.queuename);
11192  if (!q) {
11193  ast_log(LOG_WARNING, "QueueUpdate could not find requested queue '%s'\n", args.queuename);
11194  return 0;
11195  }
11196 
11197  ao2_lock(q);
11198  if (q->members) {
11199  struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
11200  while ((mem = ao2_iterator_next(&mem_iter))) {
11201  if (!strcasecmp(mem->membername, args.agent)) {
11202  if (!strcasecmp(args.status, "ANSWER")) {
11203  oldtalktime = q->talktime;
11204  q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
11205  time(&mem->lastcall);
11206  mem->calls++;
11207  mem->lastqueue = q;
11208  q->callscompleted++;
11209 
11210  if (newtalktime <= q->servicelevel) {
11211  q->callscompletedinsl++;
11212  }
11213  } else {
11214 
11215  time(&mem->lastcall);
11216  q->callsabandoned++;
11217  }
11218 
11219  ast_queue_log(args.queuename, args.uniqueid, args.agent, "OUTCALL", "%s|%s|%s", args.status, args.talktime, args.params);
11220  }
11221 
11222  ao2_ref(mem, -1);
11223  }
11224 
11225  ao2_iterator_destroy(&mem_iter);
11226  }
11227 
11228  ao2_unlock(q);
11229  queue_t_unref(q, "Done with temporary pointer");
11230 
11231  return 0;
11232 }
11233 
11234 static struct ast_cli_entry cli_queue[] = {
11235  AST_CLI_DEFINE(queue_show, "Show status of a specified queue"),
11236  AST_CLI_DEFINE(handle_queue_rule_show, "Show the rules defined in queuerules.conf"),
11237  AST_CLI_DEFINE(handle_queue_add_member, "Add a channel to a specified queue"),
11238  AST_CLI_DEFINE(handle_queue_remove_member, "Removes a channel from a specified queue"),
11239  AST_CLI_DEFINE(handle_queue_pause_member, "Pause or unpause a queue member"),
11240  AST_CLI_DEFINE(handle_queue_set_member_penalty, "Set penalty for a channel of a specified queue"),
11241  AST_CLI_DEFINE(handle_queue_set_member_ringinuse, "Set ringinuse for a channel of a specified queue"),
11242  AST_CLI_DEFINE(handle_queue_reload, "Reload queues, members, queue rules, or parameters"),
11243  AST_CLI_DEFINE(handle_queue_reset, "Reset statistics for a queue"),
11244  AST_CLI_DEFINE(handle_queue_change_priority_caller, "Change priority caller on queue"),
11245 };
11246 
11249 
11250 static int unload_module(void)
11251 {
11253  agent_router = NULL;
11254 
11255  topic_forwarder = stasis_forward_cancel(topic_forwarder);
11256 
11257  STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_join_type);
11258  STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_leave_type);
11259  STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_abandon_type);
11260 
11261  STASIS_MESSAGE_TYPE_CLEANUP(queue_member_status_type);
11262  STASIS_MESSAGE_TYPE_CLEANUP(queue_member_added_type);
11263  STASIS_MESSAGE_TYPE_CLEANUP(queue_member_removed_type);
11264  STASIS_MESSAGE_TYPE_CLEANUP(queue_member_pause_type);
11265  STASIS_MESSAGE_TYPE_CLEANUP(queue_member_penalty_type);
11266  STASIS_MESSAGE_TYPE_CLEANUP(queue_member_ringinuse_type);
11267 
11268  STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_called_type);
11269  STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_connect_type);
11270  STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_complete_type);
11271  STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_dump_type);
11272  STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_ringnoanswer_type);
11273 
11274  ast_cli_unregister_multiple(cli_queue, ARRAY_LEN(cli_queue));
11275  ast_manager_unregister("QueueStatus");
11276  ast_manager_unregister("QueueRule");
11277  ast_manager_unregister("QueueSummary");
11278  ast_manager_unregister("QueueAdd");
11279  ast_manager_unregister("QueueRemove");
11280  ast_manager_unregister("QueuePause");
11281  ast_manager_unregister("QueueLog");
11282  ast_manager_unregister("QueueUpdate");
11283  ast_manager_unregister("QueuePenalty");
11284  ast_manager_unregister("QueueReload");
11285  ast_manager_unregister("QueueReset");
11286  ast_manager_unregister("QueueMemberRingInUse");
11287  ast_manager_unregister("QueueChangePriorityCaller");
11288  ast_unregister_application(app_aqm);
11289  ast_unregister_application(app_rqm);
11290  ast_unregister_application(app_pqm);
11291  ast_unregister_application(app_upqm);
11293  ast_unregister_application(app_qupd);
11295  ast_custom_function_unregister(&queueexists_function);
11296  ast_custom_function_unregister(&queuevar_function);
11297  ast_custom_function_unregister(&queuemembercount_function);
11298  ast_custom_function_unregister(&queuemembercount_dep);
11299  ast_custom_function_unregister(&queuememberlist_function);
11300  ast_custom_function_unregister(&queuegetchannel_function);
11301  ast_custom_function_unregister(&queuewaitingcount_function);
11302  ast_custom_function_unregister(&queuememberpenalty_function);
11303 
11304  device_state_sub = stasis_unsubscribe_and_join(device_state_sub);
11305 
11306  ast_unload_realtime("queue_members");
11307  ao2_cleanup(queues);
11308  ao2_cleanup(pending_members);
11309 
11310  queues = NULL;
11311  return 0;
11312 }
11313 
11314 /*!
11315  * \brief Load the module
11316  *
11317  * Module loading including tests for configuration or dependencies.
11318  * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
11319  * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
11320  * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
11321  * configuration file or other non-critical problem return
11322  * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
11323  */
11324 static int load_module(void)
11325 {
11326  int err = 0;
11327  struct ast_flags mask = {AST_FLAGS_ALL, };
11328  struct ast_config *member_config;
11329  struct stasis_topic *queue_topic;
11330  struct stasis_topic *manager_topic;
11331 
11334  if (!queues) {
11335  return AST_MODULE_LOAD_DECLINE;
11336  }
11337 
11340  if (!pending_members) {
11341  unload_module();
11342  return AST_MODULE_LOAD_DECLINE;
11343  }
11344 
11345  use_weight = 0;
11346 
11347  if (reload_handler(0, &mask, NULL)) {
11348  unload_module();
11349  return AST_MODULE_LOAD_DECLINE;
11350  }
11351 
11352  ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, SENTINEL);
11353 
11354  /*
11355  * This section is used to determine which name for 'ringinuse' to use in realtime members
11356  * Necessary for supporting older setups.
11357  */
11358  member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name LIKE", "%", SENTINEL);
11359  if (!member_config) {
11360  realtime_ringinuse_field = "ringinuse";
11361  } else {
11362  const char *config_val;
11363 
11364  if ((config_val = ast_variable_retrieve(member_config, NULL, "ringinuse"))) {
11365  ast_log(LOG_NOTICE, "ringinuse field entries found in queue_members table. Using 'ringinuse'\n");
11366  realtime_ringinuse_field = "ringinuse";
11367  } else if ((config_val = ast_variable_retrieve(member_config, NULL, "ignorebusy"))) {
11368  ast_log(LOG_NOTICE, "ignorebusy field found in queue_members table with no ringinuse field. Using 'ignorebusy'\n");
11369  realtime_ringinuse_field = "ignorebusy";
11370  } else {
11371  ast_log(LOG_NOTICE, "No entries were found for ringinuse/ignorebusy in queue_members table. Using 'ringinuse'\n");
11372  realtime_ringinuse_field = "ringinuse";
11373  }
11374  }
11375  ast_config_destroy(member_config);
11376 
11377  if (queue_persistent_members) {
11379  }
11380 
11381  err |= ast_cli_register_multiple(cli_queue, ARRAY_LEN(cli_queue));
11383  err |= ast_register_application_xml(app_aqm, aqm_exec);
11384  err |= ast_register_application_xml(app_rqm, rqm_exec);
11385  err |= ast_register_application_xml(app_pqm, pqm_exec);
11386  err |= ast_register_application_xml(app_upqm, upqm_exec);
11387  err |= ast_register_application_xml(app_ql, ql_exec);
11388  err |= ast_register_application_xml(app_qupd, qupd_exec);
11389  err |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status);
11390  err |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary);
11397  err |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show);
11398  err |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload);
11399  err |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset);
11400  err |= ast_manager_register_xml("QueueChangePriorityCaller", 0, manager_change_priority_caller_on_queue);
11401  err |= ast_custom_function_register(&queuevar_function);
11402  err |= ast_custom_function_register(&queueexists_function);
11403  err |= ast_custom_function_register(&queuemembercount_function);
11404  err |= ast_custom_function_register(&queuemembercount_dep);
11405  err |= ast_custom_function_register(&queuememberlist_function);
11406  err |= ast_custom_function_register(&queuegetchannel_function);
11407  err |= ast_custom_function_register(&queuewaitingcount_function);
11408  err |= ast_custom_function_register(&queuememberpenalty_function);
11409 
11410  /* in the following subscribe call, do I use DEVICE_STATE, or DEVICE_STATE_CHANGE? */
11412  if (!device_state_sub) {
11413  err = -1;
11414  }
11417 
11418  manager_topic = ast_manager_get_topic();
11419  queue_topic = ast_queue_topic_all();
11420  if (!manager_topic || !queue_topic) {
11421  unload_module();
11422  return AST_MODULE_LOAD_DECLINE;
11423  }
11424  topic_forwarder = stasis_forward_all(queue_topic, manager_topic);
11425  if (!topic_forwarder) {
11426  unload_module();
11427  return AST_MODULE_LOAD_DECLINE;
11428  }
11429 
11432  unload_module();
11433  return AST_MODULE_LOAD_DECLINE;
11434  }
11436  if (!agent_router) {
11437  unload_module();
11438  return AST_MODULE_LOAD_DECLINE;
11439  }
11440  err |= stasis_message_router_add(agent_router,
11443  NULL);
11444  err |= stasis_message_router_add(agent_router,
11447  NULL);
11448 
11449  err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_join_type);
11450  err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_leave_type);
11451  err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_abandon_type);
11452 
11453  err |= STASIS_MESSAGE_TYPE_INIT(queue_member_status_type);
11454  err |= STASIS_MESSAGE_TYPE_INIT(queue_member_added_type);
11455  err |= STASIS_MESSAGE_TYPE_INIT(queue_member_removed_type);
11456  err |= STASIS_MESSAGE_TYPE_INIT(queue_member_pause_type);
11457  err |= STASIS_MESSAGE_TYPE_INIT(queue_member_penalty_type);
11458  err |= STASIS_MESSAGE_TYPE_INIT(queue_member_ringinuse_type);
11459 
11460  err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_called_type);
11461  err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_connect_type);
11462  err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_complete_type);
11463  err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_dump_type);
11464  err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_ringnoanswer_type);
11465 
11466  if (err) {
11467  unload_module();
11468  return AST_MODULE_LOAD_DECLINE;
11469  }
11470  return AST_MODULE_LOAD_SUCCESS;
11471 }
11472 
11473 static int reload(void)
11474 {
11475  struct ast_flags mask = {AST_FLAGS_ALL & ~QUEUE_RESET_STATS,};
11476  ast_unload_realtime("queue_members");
11477  reload_handler(1, &mask, NULL);
11478  return 0;
11479 }
11480 
11481 /* \brief Find a member by looking up queuename and interface.
11482  * \return Returns a member or NULL if member not found.
11483 */
11484 static struct member *find_member_by_queuename_and_interface(const char *queuename, const char *interface)
11485 {
11486  struct member *mem = NULL;
11487  struct call_queue *q;
11488 
11489  if ((q = find_load_queue_rt_friendly(queuename))) {
11490  ao2_lock(q);
11491  mem = ao2_find(q->members, interface, OBJ_KEY);
11492  ao2_unlock(q);
11493  queue_t_unref(q, "Expiring temporary reference.");
11494  }
11495  return mem;
11496 }
11497 
11499  .support_level = AST_MODULE_SUPPORT_CORE,
11500  .load = load_module,
11501  .unload = unload_module,
11502  .reload = reload,
11503  .load_pri = AST_MODPRI_DEVSTATE_CONSUMER,
11504  .optional_modules = "res_monitor",
11505 );
const char * name
Definition: pbx.h:119
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
static int get_member_penalty(char *queuename, char *interface)
Definition: app_queue.c:7740
struct ast_str * sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS]
Definition: app_queue.c:1698
struct ast_variable * ast_load_realtime(const char *family,...) attribute_sentinel
Definition: main/config.c:3339
static int queue_function_qac_dep(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Get the total number of members in a specific queue (Deprecated)
Definition: app_queue.c:8806
struct ast_variable * next
struct stasis_message_type * ast_blind_transfer_type(void)
Message type for ast_blind_transfer_message.
int ast_safe_sleep(struct ast_channel *chan, int ms)
Wait for a specified amount of time, looking for hangups.
Definition: channel.c:1574
struct ast_channel * ast_waitfor_n(struct ast_channel **chan, int n, int *ms)
Waits for input on a group of channels Wait for input on an array of channels for a given # of millis...
Definition: channel.c:3166
static struct ast_manager_event_blob * queue_member_added_to_ami(struct stasis_message *message)
Definition: app_queue.c:2040
struct callattempt * q_next
Definition: app_queue.c:1538
static const char type[]
Definition: chan_ooh323.c:109
int queuepos
Definition: app_queue.c:1606
Struct containing info for an AMI event to send out.
Definition: manager.h:491
enum sip_cc_notify_state state
Definition: chan_sip.c:959
void ast_party_connected_line_init(struct ast_party_connected_line *init)
Initialize the given connected line structure.
Definition: channel.c:2022
static void queue_stasis_data_destructor(void *obj)
Definition: app_queue.c:5994
static void do_print(struct mansession *s, int fd, const char *str)
direct ouput to manager or cli with proper terminator
Definition: app_queue.c:9644
static int say_position(struct queue_ent *qe, int ringing)
Definition: app_queue.c:3980
char digit
const char * ast_devstate2str(enum ast_device_state devstate) attribute_pure
Convert device state to text string for output.
Definition: devicestate.c:237
int servicelevel
Definition: app_queue.c:1731
void ast_set_callerid(struct ast_channel *chan, const char *cid_num, const char *cid_name, const char *cid_ani)
Set caller ID number, name and ANI and generate AMI event.
Definition: channel.c:7434
struct call_queue * parent
Definition: app_queue.c:1561
#define ast_channel_lock(chan)
Definition: channel.h:2945
#define X_REC_IN
Definition: monitor.h:30
void ast_channel_req_accountcodes_precious(struct ast_channel *chan, const struct ast_channel *requestor, enum ast_channel_requestor_relationship relationship)
Setup new channel accountcodes from the requestor channel after ast_request().
Definition: channel.c:6531
int dynamic
Definition: app_queue.c:1601
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:118
Main Channel structure associated with a channel.
struct ast_party_dialed::@246 number
Dialed/Called number.
Local proxy channel special access.
static struct ast_custom_function queuewaitingcount_function
Definition: app_queue.c:9105
Music on hold handling.
static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
Definition: app_queue.c:3757
static int change_priority_caller_on_queue(const char *queuename, const char *caller, int priority)
Change priority caller into a queue.
Definition: app_queue.c:7430
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
ast_device_state
Device States.
Definition: devicestate.h:52
static int member_hash_fn(const void *obj, const int flags)
Definition: app_queue.c:2740
int ast_max_forwards_get(struct ast_channel *chan)
Get the current max forwards for a particular channel.
Definition: max_forwards.c:121
char * str
Subscriber phone number (Malloced)
Definition: channel.h:292
static struct member * create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface, int ringinuse, int wrapuptime)
allocate space for new queue member and set fields based on parameters passed
Definition: app_queue.c:2686
static void queue_publish_multi_channel_snapshot_blob(struct stasis_topic *topic, struct ast_channel_snapshot *caller_snapshot, struct ast_channel_snapshot *agent_snapshot, struct stasis_message_type *type, struct ast_json *blob)
Definition: app_queue.c:2166
static int qupd_exec(struct ast_channel *chan, const char *data)
Update Queue with data of an outgoing call.
Definition: app_queue.c:11157
static void handle_blind_transfer(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Handle a blind transfer event.
Definition: app_queue.c:6146
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1250
#define MAX_PERIODIC_ANNOUNCEMENTS
Definition: app_queue.c:1432
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
static char * app_ql
Definition: app_queue.c:1458
static int store_next_rr(struct queue_ent *qe, struct callattempt *outgoing)
Search for best metric and add to Round Robbin queue.
Definition: app_queue.c:4699
const char *const type
Definition: channel.h:630
struct ast_channel_snapshot_base * base
Asterisk locking-related definitions:
int raise_penalty
Definition: app_queue.c:1580
int autopause
Definition: app_queue.c:1421
union ast_attended_transfer_message::@324 dest
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3080
Asterisk main include file. File version handling, generic pbx functions.
int callsabandonedinsl
Definition: app_queue.c:1730
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:420
static int manager_queue_member_ringinuse(struct mansession *s, const struct message *m)
Definition: app_queue.c:10457
static struct ast_manager_event_blob * queue_member_status_to_ami(struct stasis_message *message)
Definition: app_queue.c:2035
int paused
Definition: app_queue.c:1604
#define RES_OKAY
Definition: app_queue.c:1441
int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *connected_info, int is_caller, int frame)
Run a connected line interception macro and update a channel&#39;s connected line information.
Definition: channel.c:10435
#define stasis_message_router_create_pool(topic)
static int rqm_exec(struct ast_channel *chan, const char *data)
RemoveQueueMember application.
Definition: app_queue.c:7954
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
char digits[AST_MAX_EXTENSION]
Definition: app_queue.c:1565
static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
Definition: app_queue.c:6568
char * str
Subscriber phone number (Malloced)
Definition: channel.h:387
const ast_string_field sound_holdtime
Definition: app_queue.c:1696
void ast_channel_set_caller_event(struct ast_channel *chan, const struct ast_party_caller *caller, const struct ast_set_party_caller *update)
Set the caller id information in the Asterisk channel and generate an AMI event if the caller id name...
Definition: channel.c:7472
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
static struct call_queue * find_load_queue_rt_friendly(const char *queuename)
Definition: app_queue.c:3702
struct ast_channel * chan
Definition: app_queue.c:1586
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:591
static const struct @66 queue_results[]
int min_penalty
Definition: app_queue.c:1579
static char * app_qupd
Definition: app_queue.c:1460
int wrapuptime
Definition: app_queue.c:1737
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
Definition: pbx_app.c:471
static int mark_member_dead(void *obj, void *arg, int flags)
Definition: app_queue.c:9351
const ast_string_field membergosub
Definition: app_queue.c:1696
struct ast_flags features_callee
Definition: channel.h:1079
String manipulation functions.
static char * handle_queue_add_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:10561
int max_relative
Definition: app_queue.c:1645
struct stasis_message_type * ast_channel_entered_bridge_type(void)
Message type for channel enter bridge blob messages.
static int load_module(void)
Load the module.
Definition: app_queue.c:11324
static char * handle_queue_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:11090
static int set_member_ringinuse_help_members(struct call_queue *q, const char *interface, int ringinuse)
Definition: app_queue.c:7635
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
Message representing attended transfer.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1263
static struct ast_manager_event_blob * queue_member_penalty_to_ami(struct stasis_message *message)
Definition: app_queue.c:2055
struct stasis_message_router * bridge_router
Definition: app_queue.c:5981
Definition: ast_expr2.c:325
struct ast_channel_snapshot * channel
static char * app_aqm
Definition: app_queue.c:1450
#define ao2_t_alloc(data_size, destructor_fn, debug_msg)
Definition: astobj2.h:409
int max_penalty
Definition: app_queue.c:1578
static struct ao2_container * pending_members
Definition: app_queue.c:2375
struct ast_party_id id
Connected party ID.
Definition: channel.h:459
int last_periodic_announce_sound
Definition: app_queue.c:1573
#define AST_DIGIT_ANY
Definition: file.h:48
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
static void handle_hangup(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6398
static struct ast_custom_function queuegetchannel_function
Definition: app_queue.c:9100
time_t start
Definition: app_queue.c:1583
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
static struct ast_manager_event_blob * queue_multi_channel_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2084
struct ast_json_payload * ast_json_payload_create(struct ast_json *json)
Create an ao2 object to pass json blobs as data payloads for stasis.
Definition: json.c:735
void ast_party_connected_line_set_init(struct ast_party_connected_line *init, const struct ast_party_connected_line *guide)
Initialize the given connected line structure using the given guide for a set update operation...
Definition: channel.c:2045
#define ast_test_flag(p, flag)
Definition: utils.h:63
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1216
char exten[AST_MAX_EXTENSION]
int penaltymemberslimit
Definition: app_queue.c:1738
Device state management.
unsigned int autopauseunavail
Definition: app_queue.c:1716
Support for translation of data formats. translate.c.
static int upqm_exec(struct ast_channel *chan, const char *data)
UnPauseQueueMember application.
Definition: app_queue.c:7918
#define BEGIN_OPTIONS
Message published during a blind transfer.
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4322
char name[80]
Definition: app_queue.c:1759
#define MAX_MUSICCLASS
Definition: channel.h:174
unsigned int setqueuevar
Definition: app_queue.c:1703
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
struct ast_party_name name
Subscriber name.
Definition: channel.h:341
#define OBJ_KEY
Definition: astobj2.h:1155
#define DEFAULT_RETRY
Definition: app_queue.c:1429
void ast_channel_publish_cached_blob(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
Publish a channel blob message using the latest snapshot from the cache.
#define ANNOUNCEPOSITION_NO
Definition: app_queue.c:1652
struct ast_party_id from
Who is redirecting the call (Sent to the party the call is redirected toward)
Definition: channel.h:528
void ast_channel_publish_dial(struct ast_channel *caller, struct ast_channel *peer, const char *dialstring, const char *dialstatus)
Publish in the ast_channel_topic or ast_channel_topic_all topics a stasis message for the channels in...
int ast_extension_state_del(int id, ast_state_cb_type change_cb)
Deletes a state change watcher by ID.
Definition: pbx.c:3858
static void queue_bridge_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6261
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static char * complete_queue_pause_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:10799
void ast_channel_appl_set(struct ast_channel *chan, const char *value)
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
static struct ast_manager_event_blob * queue_member_removed_to_ami(struct stasis_message *message)
Definition: app_queue.c:2045
char state_interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1596
struct ast_json * blob
static const struct strategy strategies[]
static struct ast_manager_event_blob * queue_caller_abandon_to_ami(struct stasis_message *message)
Definition: app_queue.c:2005
static void update_realtime_members(struct call_queue *q)
Definition: app_queue.c:3773
int stasis_message_router_add(struct stasis_message_router *router, struct stasis_message_type *message_type, stasis_subscription_cb callback, void *data)
Add a route to a message router.
static char * handle_queue_remove_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:10687
void ast_channel_update_redirecting(struct ast_channel *chan, const struct ast_party_redirecting *redirecting, const struct ast_set_party_redirecting *update)
Indicate that the redirecting id has changed.
Definition: channel.c:10379
static int reload(void)
Definition: app_queue.c:11473
#define DEFAULT_MIN_ANNOUNCE_FREQUENCY
The minimum number of seconds between position announcements.
Definition: app_queue.c:1437
unsigned int announceposition_only_up
Definition: app_queue.c:1710
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1501
int wrapuptime
Definition: app_queue.c:1608
struct ast_channel_snapshot * snapshot
#define OBJ_POINTER
Definition: astobj2.h:1154
static void queue_rules_set_global_params(struct ast_config *cfg)
Definition: app_queue.c:9128
static int manager_queue_reset(struct mansession *s, const struct message *m)
Definition: app_queue.c:10411
int ast_channel_supports_html(struct ast_channel *channel)
Checks for HTML support on a channel.
Definition: channel.c:6720
int min_relative
Definition: app_queue.c:1646
#define ast_set_flag(p, flag)
Definition: utils.h:70
int minannouncefrequency
Definition: app_queue.c:1721
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
static struct ast_manager_event_blob * queue_caller_leave_to_ami(struct stasis_message *message)
Definition: app_queue.c:2000
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition: manager.c:3237
static struct ast_manager_event_blob * queue_agent_complete_to_ami(struct stasis_message *message)
Definition: app_queue.c:2135
int last_pos_said
Definition: app_queue.c:1570
descriptor for a cli entry.
Definition: cli.h:171
const int argc
Definition: cli.h:160
#define LOG_WARNING
Definition: logger.h:274
static int manager_queue_member_penalty(struct mansession *s, const struct message *m)
Definition: app_queue.c:10491
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
#define AST_MAX_WATCHERS
Definition: app_queue.c:4923
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
AST_JSON_INT_T ast_json_int_t
Primarily used to cast when packing to an "I" type.
Definition: json.h:87
static void member_remove_from_queue(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:3376
static int negative_penalty_invalid
queues.conf [general] option
Definition: app_queue.c:1487
int linwrapped
Definition: app_queue.c:1582
void ast_db_freetree(struct ast_db_entry *entry)
Free structure created by ast_db_gettree()
Definition: main/db.c:598
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
void ast_channel_update_connected_line(struct ast_channel *chan, const struct ast_party_connected_line *connected, const struct ast_set_party_connected_line *update)
Indicate that the connected line information has changed.
Definition: channel.c:9189
int ast_unload_realtime(const char *family)
Release any resources cached for a realtime family.
Definition: main/config.c:3406
#define CONFIG_STATUS_FILEINVALID
#define COLOR_CYAN
Definition: term.h:59
int autopause
Definition: app_queue.c:1743
unsigned int ringinuse
Definition: app_queue.c:1700
static int kill_dead_members(void *obj, void *arg, int flags)
Definition: app_queue.c:9360
enum ast_device_state state
Definition: devicestate.h:250
empty_conditions
Definition: app_queue.c:1619
static int tmp()
Definition: bt_open.c:389
static struct ast_manager_event_blob * queue_caller_join_to_ami(struct stasis_message *message)
Definition: app_queue.c:1995
#define RES_NOT_DYNAMIC
Definition: app_queue.c:1445
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Definition: astobj2.h:1335
time_t expire
Definition: app_queue.c:1584
#define MAX_QUEUE_BUCKETS
Definition: app_queue.c:1439
enum ast_state_cb_update_reason reason
Definition: pbx.h:103
unsigned int timeoutrestart
Definition: app_queue.c:1707
void stasis_message_router_unsubscribe_and_join(struct stasis_message_router *router)
Unsubscribe the router from the upstream topic, blocking until the final message has been processed...
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
Definition: main/config.c:3363
int ast_call(struct ast_channel *chan, const char *addr, int timeout)
Make a call.
Definition: channel.c:6553
Structure for variables, used for configurations and for channel variables.
struct stasis_topic * ast_queue_topic_all(void)
Get the Stasis Message Bus API topic for queue messages.
Definition: main/app.c:3184
static void queue_reset_global_params(void)
Definition: app_queue.c:9201
#define var
Definition: ast_expr2f.c:614
struct ast_json * json
Definition: json.h:1025
Structure representing a snapshot of channel state.
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:894
static struct ast_custom_function queuemembercount_dep
Definition: app_queue.c:9095
#define queue_ref(q)
Definition: app_queue.c:1918
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:438
static int log_membername_as_agent
queues.conf [general] option
Definition: app_queue.c:1490
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4302
struct ast_str * ast_manager_build_channel_state_string_prefix(const struct ast_channel_snapshot *snapshot, const char *prefix)
Generate the AMI message body from a channel snapshot.
static int queue_function_exists(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Check if a given queue exists.
Definition: app_queue.c:8599
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition: stasis.h:1523
static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
Calculate the metric of each member in the outgoing callattempts.
Definition: app_queue.c:5779
Definition: cli.h:152
void * ast_aoc_destroy_decoded(struct ast_aoc_decoded *decoded)
free an ast_aoc_decoded object
Definition: aoc.c:307
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
Definition: stasis.c:1079
unsigned int announceholdtime
Definition: app_queue.c:1708
ast_channel_state
ast_channel states
Definition: channelstate.h:35
static int reload_queue_rules(int reload)
Reload the rules defined in queuerules.conf.
Definition: app_queue.c:9142
char * str
Subscriber name (Malloced)
Definition: channel.h:265
unsigned int stop
Definition: app_meetme.c:1096
int ast_indicate_data(struct ast_channel *chan, int condition, const void *data, size_t datalen)
Indicates condition of channel, with payload.
Definition: channel.c:4698
static int mark_unfound(void *obj, void *arg, int flags)
Definition: app_queue.c:9506
Definition: astman.c:222
#define queue_unref(q)
Definition: app_queue.c:1919
Dialing API.
int ast_db_get_allocated(const char *family, const char *key, char **out)
Get key value specified by family/key as a heap allocated string.
Definition: main/db.c:422
char interface[256]
Definition: app_queue.c:1541
const ast_string_field uniqueid
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1091
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
static char * __queues_show(struct mansession *s, int fd, int argc, const char *const *argv)
Show queue(s) status and statistics.
Definition: app_queue.c:9758
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
const char * ast_hangup_cause_to_dial_status(int hangup_cause)
Convert a hangup cause to a publishable dial status.
Definition: dial.c:753
#define queue_t_ref(q, tag)
Definition: app_queue.c:1920
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:337
struct rule_list::@71 rules
#define COLOR_GREEN
Definition: term.h:51
static void reload_single_member(const char *memberdata, struct call_queue *q)
reload information pertaining to a single member
Definition: app_queue.c:9244
queue_result
Definition: app_queue.c:1495
int realtime
Definition: app_queue.c:1602
#define ast_assert(a)
Definition: utils.h:695
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3191
static char * handle_queue_change_priority_caller(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:10750
#define ao2_unlock(a)
Definition: astobj2.h:730
unsigned int setinterfacevar
Definition: app_queue.c:1702
static struct test_val c
int ast_start_mixmonitor(struct ast_channel *chan, const char *filename, const char *options)
Start a mixmonitor on a channel with the given parameters.
Definition: mixmonitor.c:74
char * text
Definition: app_queue.c:1508
#define ast_str_alloca(init_len)
Definition: strings.h:800
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:98
static int setup_stasis_subs(struct queue_ent *qe, struct ast_channel *peer, struct member *mem, time_t holdstart, time_t starttime, int callcompletedinsl)
Definition: app_queue.c:6514
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
static int call(void *data)
Definition: chan_pjsip.c:2358
void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
Destroy the connected line information contents.
Definition: channel.c:2072
static void set_queue_result(struct ast_channel *chan, enum queue_result res)
sets the QUEUESTATUS channel variable
Definition: app_queue.c:1775
const char * str
Definition: app_jack.c:147
static int queue_function_memberpenalty_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty.
Definition: app_queue.c:9011
char bridge[AST_UUID_STR_LEN]
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
static int queue_delme_members_decrement_followers(void *obj, void *arg, int flag)
Definition: app_queue.c:1887
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3328
unsigned int dead
Definition: app_queue.c:1613
const char * args
struct ast_aoc_decoded * aoc_s_rate_list
Definition: app_queue.c:1554
static const struct ast_app_option queue_exec_options[128]
Definition: app_queue.c:1379
static int say_periodic_announcement(struct queue_ent *qe, int ringing)
Playback announcement to queued members if period has elapsed.
Definition: app_queue.c:4747
#define NULL
Definition: resample.c:96
static struct stasis_topic * manager_topic
A stasis_topic that all topics AMI cares about will be forwarded to.
Definition: manager.c:1490
const ast_string_field sound_thanks
Definition: app_queue.c:1696
static void clear_queue(struct call_queue *q)
Definition: app_queue.c:2863
int value
Definition: syslog.c:37
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
static int can_ring_entry(struct queue_ent *qe, struct callattempt *call)
Definition: app_queue.c:4388
#define AST_FRAME_DTMF
static int input(yyscan_t yyscanner)
Definition: ast_expr2f.c:1584
static char * app_rqm
Definition: app_queue.c:1452
int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block)
Sets an option on a channel.
Definition: channel.c:7522
static char * queue_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:9974
static void handle_masquerade(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6455
unsigned int delme
Definition: app_queue.c:1614
static int priority
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
unsigned int announce_to_first_user
Definition: app_queue.c:1701
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7876
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:614
struct ao2_container * members
Definition: app_queue.c:1752
const char * ast_channel_call_forward(const struct ast_channel *chan)
struct queue_ent * head
Definition: app_queue.c:1753
int ast_channel_priority(const struct ast_channel *chan)
char monfmt[8]
Definition: app_queue.c:1733
int ast_update_realtime(const char *family, const char *keyfield, const char *lookup,...) attribute_sentinel
Update realtime configuration.
Definition: main/config.c:3489
static void pending_members_remove(struct member *mem)
Definition: app_queue.c:2426
#define ast_verb(level,...)
Definition: logger.h:463
struct ast_bridge_channel_snapshot_pair to_transferee
static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
Definition: app_queue.c:4128
int callscompletedinsl
Definition: app_queue.c:1732
const ast_string_field membermacro
Definition: app_queue.c:1696
struct ast_manager_event_blob * ast_manager_event_blob_create(int event_flags, const char *manager_event, const char *extra_fields_fmt,...)
Construct a ast_manager_event_blob.
Definition: manager.c:9727
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:755
int announcepositionlimit
Definition: app_queue.c:1719
static int queue_function_mem_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
Dialplan function QUEUE_MEMBER() Sets the members penalty / paused / ringinuse.
Definition: app_queue.c:8743
static int insert_penaltychange(const char *list_name, const char *content, const int linenum)
Change queue penalty by adding rule.
Definition: app_queue.c:2895
const char * line
Definition: cli.h:162
static struct ast_custom_function queueexists_function
Definition: app_queue.c:9079
static void rt_handle_member_record(struct call_queue *q, char *category, struct ast_config *member_config)
Find rt member record to update otherwise create one.
Definition: app_queue.c:3392
struct ast_channel_snapshot * ast_channel_snapshot_create(struct ast_channel *chan)
Generate a snapshot of the channel state. This is an ao2 object, so ao2_cleanup() to deallocate...
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
char membername[80]
Definition: app_queue.c:1598
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1593
int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Looks for a valid matching extension.
Definition: pbx.c:4194
static void update_connected_line_from_peer(struct ast_channel *chan, struct ast_channel *peer, int is_caller)
Definition: app_queue.c:4906
struct ast_json * ast_multi_channel_blob_get_json(struct ast_multi_channel_blob *obj)
Retrieve the JSON blob from a ast_multi_channel_blob. Returned ast_json is still owned by obj...
static struct stasis_forward * topic_forwarder
Definition: app_queue.c:11248
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
struct ast_frame_subclass subclass
#define X_REC_OUT
Definition: monitor.h:31
static int strat2int(const char *strategy)
Definition: app_queue.c:1800
static int extension_state_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
Definition: app_queue.c:2627
#define RES_OUTOFMEMORY
Definition: app_queue.c:1443
Utility functions.
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:269
Blob of data associated with a channel.
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
#define ast_strlen_zero(foo)
Definition: strings.h:52
static int member_status_available(int status)
Definition: app_queue.c:4374
struct ast_channel * ast_request(const char *type, struct ast_format_cap *request_cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause)
Requests a channel.
Definition: channel.c:6444
const char * source_chan_uniqueid
Definition: app_queue.c:5935
struct timeval * ast_channel_whentohangup(struct ast_channel *chan)
static char * app
Definition: app_queue.c:1448
unsigned int wrapped
Definition: app_queue.c:1706
static int manager_queue_rule_show(struct mansession *s, const struct message *m)
Definition: app_queue.c:9990
struct ast_str * ast_manager_str_from_json_object(struct ast_json *blob, key_exclusion_cb exclusion_cb)
Convert a JSON object into an AMI compatible string.
Definition: manager.c:1821
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
static char * handle_queue_set_member_ringinuse(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:10896
Number structure.
Definition: app_followme.c:154
const struct ast_channel_tech * tech
static int wait_a_bit(struct queue_ent *qe)
Definition: app_queue.c:7229
static struct ast_manager_event_blob * queue_channel_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:1976
#define ao2_bump(obj)
Definition: astobj2.h:491
static struct callattempt * wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
Wait for a member to answer the call.
Definition: app_queue.c:4937
static int compare_weight(struct call_queue *rq, struct member *member)
Definition: app_queue.c:4323
int holdtime
Definition: app_queue.c:1726
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1065
struct ast_party_id id
Caller party ID.
Definition: channel.h:421
static int queue_function_var(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
create interface var with all queue details.
Definition: app_queue.c:8555
static int queue_function_memberpenalty_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
Dialplan function QUEUE_MEMBER_PENALTY() Sets the members penalty.
Definition: app_queue.c:9043
struct ast_bridge_channel_snapshot_pair to_transfer_target
Configuration File Parser.
enum ast_extension_states exten_state
Definition: pbx.h:104
int ast_channel_datastore_inherit(struct ast_channel *from, struct ast_channel *to)
Inherit datastores from a parent to a child.
Definition: channel.c:2373
struct stasis_message_type * ast_device_state_message_type(void)
Get the Stasis message type for device state messages.
#define RES_NOT_CALLER
Definition: app_queue.c:1446
struct ast_bridge_snapshot * bridge
static char * realtime_ringinuse_field
name of the ringinuse field in the realtime database
Definition: app_queue.c:1493
struct stasis_topic * ast_channel_topic_all(void)
A topic which publishes the events for all channels.
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
enum ast_transfer_result result
void ast_replace_subargument_delimiter(char *s)
Replace &#39;^&#39; in a string with &#39;,&#39;.
Definition: main/utils.c:2095
#define ast_log
Definition: astobj2.c:42
const char * predial_callee
Definition: app_queue.c:1566
static void member_add_to_queue(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:3360
#define SENTINEL
Definition: compiler.h:87
struct ast_db_entry * next
Definition: astdb.h:32
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1120
Generic Advice of Charge encode and decode routines.
#define ast_config_load(filename, flags)
Load a config file.
const ast_string_field sound_minute
Definition: app_queue.c:1696
struct ast_party_connected_line connected
Definition: app_queue.c:1545
int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *peer)
Make the frame formats of two channels compatible.
Definition: channel.c:6817
struct ast_aoc_decoded * ast_aoc_decode(struct ast_aoc_encoded *encoded, size_t size, struct ast_channel *chan)
decodes an encoded aoc payload.
Definition: aoc.c:449
int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt,...)
Tells Asterisk the State for Device is changed.
Definition: devicestate.c:510
static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
Configure a queue parameter.
Definition: app_queue.c:3144
static struct ast_manager_event_blob * queue_member_pause_to_ami(struct stasis_message *message)
Definition: app_queue.c:2050
static struct ast_custom_function queuemembercount_function
Definition: app_queue.c:9089
struct ast_party_id ani
Automatic Number Identification (ANI)
Definition: channel.h:428
agent_complete_reason
Definition: app_queue.c:5857
int periodicannouncefrequency
Definition: app_queue.c:1722
static struct ao2_container * queues
Definition: app_queue.c:1766
static void end_bridge_callback(void *data)
Definition: app_queue.c:6575
General Asterisk PBX channel definitions.
struct call_queue * queue
Definition: app_queue.c:5967
int ast_realtime_require_field(const char *family,...) attribute_sentinel
Inform realtime what fields that may be stored.
Definition: main/config.c:3382
time_t lastpause
Definition: app_queue.c:1611
FILE * in
Definition: utils/frame.c:33
int penalty
Definition: app_queue.c:1599
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3245
struct ast_channel_snapshot * links[2]
static struct ast_custom_function queuememberpenalty_function
Definition: app_queue.c:9115
static int pqm_exec(struct ast_channel *chan, const char *data)
PauseQueueMember application.
Definition: app_queue.c:7882
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
static char * complete_queue_set_member_value(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:10873
int memberdelay
Definition: app_queue.c:1749
const int fd
Definition: cli.h:159
const struct ast_eid * eid
The EID of the server where this message originated.
Definition: devicestate.h:248
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:353
static char * complete_queue(const char *line, const char *word, int pos, int state, ptrdiff_t word_list_offset)
Check if a given word is in a space-delimited list.
Definition: app_queue.c:9929
struct call_queue * q
Definition: app_queue.c:6564
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
#define QUEUE_PAUSED_DEVSTATE
Definition: app_queue.c:3350
static void handle_bridge_enter(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6112
struct member * member
Definition: app_queue.c:5969
const int n
Definition: cli.h:165
struct ast_aoc_encoded * ast_aoc_encode(struct ast_aoc_decoded *decoded, size_t *out_size, struct ast_channel *chan)
encodes a decoded aoc structure so it can be passed on the wire
Definition: aoc.c:650
unsigned int block_connected_update
Definition: app_queue.c:1549
static void parse_empty_options(const char *value, enum empty_conditions *empty, int joinempty)
Definition: app_queue.c:3101
const ast_string_field sound_thereare
Definition: app_queue.c:1696
#define MAX_CALL_ATTEMPT_BUCKETS
Definition: app_queue.c:2376
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
#define AST_CAUSE_ANSWERED_ELSEWHERE
Definition: causes.h:113
int ring_when_ringing
Definition: app_queue.c:1571
void ast_multi_channel_blob_add_channel(struct ast_multi_channel_blob *obj, const char *role, struct ast_channel_snapshot *snapshot)
Add a ast_channel_snapshot to a ast_multi_channel_blob object.
static void free_members(struct call_queue *q, int all)
Iterate through queue&#39;s member list and delete them.
Definition: app_queue.c:3503
ast_mutex_t lock
Definition: app_meetme.c:1091
static struct member * interface_exists(struct call_queue *q, const char *interface)
Definition: app_queue.c:7242
static void ringing(struct ast_channel *chan)
Helper method to send a ringing indication to a channel in a bridge.
#define AST_MAX_EXTENSION
Definition: channel.h:135
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:219
const ast_string_field context
Definition: app_queue.c:1696
static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime)
update the queue status
Definition: app_queue.c:5707
int ast_channel_redirecting_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const void *redirecting_info, int is_frame)
Run a redirecting interception subroutine and update a channel&#39;s redirecting information.
Definition: channel.c:10584
int AST_OPTIONAL_API_NAME() ast_monitor_start(struct ast_channel *chan, const char *format_spec, const char *fname_base, int need_lock, int stream_action, const char *beep_id)
Start monitoring a channel.
Definition: res_monitor.c:305
Structure representing relevant data during a local channel optimization.
Definition: app_queue.c:5933
static struct stasis_message_router * agent_router
Definition: app_queue.c:11247
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:299
static struct member * find_member_by_queuename_and_interface(const char *queuename, const char *interface)
Definition: app_queue.c:11484
void ast_party_number_init(struct ast_party_number *init)
Initialize the given number structure.
Definition: channel.c:1644
bridge configuration
Definition: channel.h:1077
void * end_bridge_callback_data
Definition: channel.h:1092
Caller Party information.
Definition: channel.h:419
structure to hold extensions
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:85
unsigned int autopausebusy
Definition: app_queue.c:1715
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
void(* end_bridge_callback_data_fixup)(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
Definition: channel.h:1096
static struct ast_manager_event_blob * queue_member_ringinuse_to_ami(struct stasis_message *message)
Definition: app_queue.c:2060
In case you didn&#39;t read that giant block of text above the mansession_session struct, the struct mansession is named this solely to keep the API the same in Asterisk. This structure really represents data that is different from Manager action to Manager action. The mansession_session pointer contained within points to session-specific data.
Definition: manager.c:1625
static int reload_handler(int reload, struct ast_flags *mask, const char *queuename)
The command center for all reload operations.
Definition: app_queue.c:9627
long int ast_random(void)
Definition: main/utils.c:2064
#define ao2_lock(a)
Definition: astobj2.h:718
member_properties
Definition: app_queue.c:1630
const ast_string_field sound_next
Definition: app_queue.c:1696
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
int valid_digits
Definition: app_queue.c:1567
struct member * member
Definition: app_queue.c:1543
static struct callattempt * find_best(struct callattempt *outgoing)
find the entry with the best metric, or NULL
Definition: app_queue.c:4614
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:273
A set of macros to manage forward-linked lists.
int strategy
Definition: app_queue.c:1711
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:193
struct stasis_message_type * ast_channel_agent_login_type(void)
Message type for agent login on a channel.
struct ast_bridge_snapshot * bridge
static void queue_set_global_params(struct ast_config *cfg)
Definition: app_queue.c:9212
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
struct call_queue * lastqueue
Definition: app_queue.c:1612
AST_LIST_HEAD_NOLOCK(contactliststruct, contact)
unsigned int id
Definition: app_queue.c:5939
struct stasis_message_type * ast_channel_agent_logoff_type(void)
Message type for agent logoff on a channel.
static int unload_module(void)
Definition: app_queue.c:11250
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:4179
struct ast_party_id ani
Automatic Number Identification (ANI)
Definition: channel.h:466
int ast_app_exec_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const char *macro_args)
Run a macro on a channel, placing an optional second channel into autoservice.
Definition: main/app.c:273
Blob of data associated with a bridge.
static void destroy_queue_member_cb(void *obj)
Definition: app_queue.c:2676
#define ANNOUNCEPOSITION_MORE_THAN
Definition: app_queue.c:1653
static void rna(int rnatime, struct queue_ent *qe, struct ast_channel *peer, char *interface, char *membername, int autopause)
RNA == Ring No Answer. Common code that is executed when we try a queue member and they don&#39;t answer...
Definition: app_queue.c:4839
struct ast_str * ast_manager_build_channel_state_string(const struct ast_channel_snapshot *snapshot)
Generate the AMI message body from a channel snapshot.
int linpos
Definition: app_queue.c:1581
const ast_string_field member_uniqueid
Definition: app_queue.c:5965
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition: main/app.c:2906
struct ast_config * ast_config_new(void)
Create a new base configuration structure.
Definition: extconf.c:3276
int ast_pre_call(struct ast_channel *chan, const char *sub_args)
Execute a Gosub call on the channel before a call is placed.
Definition: channel.c:6536
void ast_channel_req_accountcodes(struct ast_channel *chan, const struct ast_channel *requestor, enum ast_channel_requestor_relationship relationship)
Setup new channel accountcodes from the requestor channel after ast_request().
Definition: channel.c:6526
void ast_channel_adsicpe_set(struct ast_channel *chan, enum ast_channel_adsicpe value)
const char * ast_channel_exten(const struct ast_channel *chan)
static void escape_and_substitute(struct ast_channel *chan, const char *input, char *output, size_t size)
Definition: app_queue.c:6617
Core PBX routines and definitions.
void ast_party_number_free(struct ast_party_number *doomed)
Destroy the party number contents.
Definition: channel.c:1691
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
#define stasis_message_router_create(topic)
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
static int queue_member_decrement_followers(void *obj, void *arg, int flag)
Definition: app_queue.c:1869
struct ast_flags features_caller
Definition: channel.h:1078
char moh[MAX_MUSICCLASS]
Definition: app_queue.c:1562
#define CONFIG_STATUS_FILEUNCHANGED
#define stasis_subscribe(topic, callback, data)
Definition: stasis.h:652
#define AST_LIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
Definition: linkedlists.h:290
#define COLOR_RED
Definition: term.h:49
int ast_bridge_call_with_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, unsigned int flags)
Bridge a call, and add additional flags to the bridge.
Definition: features.c:633
static void log_attended_transfer(struct queue_stasis_data *queue_data, struct ast_attended_transfer_message *atxfer_msg)
Definition: app_queue.c:6065
const char * ast_channel_uniqueid(const struct ast_channel *chan)
struct ast_channel_snapshot_caller * caller
enum ast_attended_transfer_dest_type dest_type
const char *const * argv
Definition: cli.h:161
static int num_available_members(struct call_queue *q)
Get the number of members available to accept a call.
Definition: app_queue.c:4290
static void handle_attended_transfer(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Handle an attended transfer event.
Definition: app_queue.c:6206
static char * handle_queue_rule_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:11016
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
static int montype_default
queues.conf [general] option
Definition: app_queue.c:1475
int ast_channel_has_role(struct ast_channel *channel, const char *role_name)
Check if a role exists on a channel.
Definition: bridge_roles.c:398
struct stasis_message_type * ast_local_optimization_end_type(void)
Message type for when a local channel optimization completes.
static void leave_queue(struct queue_ent *qe)
Caller leaving queue.
Definition: app_queue.c:4151
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7258
static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
Part 2 of ring_one.
Definition: app_queue.c:4478
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
We define a custom "local user" structure because we use it not only for keeping track of what is in ...
Definition: app_queue.c:1537
static int member_cmp_fn(void *obj1, void *obj2, int flags)
Definition: app_queue.c:2756
static char * complete_queue_rule_show(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:10994
static void destroy_queue(void *obj)
Free queue&#39;s member list then its string fields.
Definition: app_queue.c:3519
static int pending_members_hash(const void *obj, const int flags)
Definition: app_queue.c:2378
#define COLOR_BLACK
Definition: term.h:47
int ast_connected_line_parse_data(const unsigned char *data, size_t datalen, struct ast_party_connected_line *connected)
Parse connected line indication frame data.
Definition: channel.c:8881
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: main/config.c:3452
static int queue_cmp_cb(void *obj, void *arg, int flags)
Definition: app_queue.c:1843
static struct ast_json * queue_member_blob_create(struct call_queue *q, struct member *mem)
Definition: app_queue.c:2258
static int autofill_default
queues.conf [general] option
Definition: app_queue.c:1472
const ast_string_field bridge_uniqueid
Definition: app_queue.c:5965
static void handle_local_optimization_end(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6333
int raise_relative
Definition: app_queue.c:1647
struct stasis_message_router * channel_router
Definition: app_queue.c:5983
static int get_wrapuptime(struct call_queue *q, struct member *member)
Return wrapuptime.
Definition: app_queue.c:1856
#define LOG_ERROR
Definition: logger.h:285
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Definition: astobj2.h:1310
static int manager_queue_log_custom(struct mansession *s, const struct message *m)
Definition: app_queue.c:10358
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
void ast_party_caller_set_init(struct ast_party_caller *init, const struct ast_party_caller *guide)
Initialize the given caller structure using the given guide for a set update operation.
Definition: channel.c:1999
static int manager_queue_reload(struct mansession *s, const struct message *m)
Definition: app_queue.c:10379
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
char * orig_chan_name
Definition: app_queue.c:1556
static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
Definition: app_queue.c:3832
#define QUEUE_UNPAUSED_DEVSTATE
Definition: app_queue.c:3351
#define ANNOUNCEPOSITION_YES
Definition: app_queue.c:1651
unsigned int dead
Definition: app_queue.c:1699
int autopausedelay
Definition: app_queue.c:1744
static int word_in_list(const char *list, const char *word)
Check if a given word is in a space-delimited list.
Definition: app_queue.c:9870
#define AST_APP_OPTION_ARG(option, flagno, argno)
Declares an application option that accepts an argument.
static void queue_channel_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6489
#define ao2_unlink(container, obj)
Definition: astobj2.h:1598
struct ast_db_entry * ast_db_gettree(const char *family, const char *keytree)
Get a list of values within the astdb tree.
Definition: main/db.c:531
int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
Copy all object references in the src container into the dest container.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define ao2_t_iterator_next(iter, tag)
Definition: astobj2.h:1931
static void publish_dial_end_event(struct ast_channel *in, struct callattempt *outgoing, struct ast_channel *exception, const char *status)
Definition: app_queue.c:4238
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
#define QUEUE_UNKNOWN_PAUSED_DEVSTATE
Definition: app_queue.c:3352
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition: main/utils.c:2033
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
static struct ast_custom_function queuememberlist_function
Definition: app_queue.c:9110
int ast_channel_connected_line_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const void *connected_info, int frame)
Run a connected line interception subroutine and update a channel&#39;s connected line information...
Definition: channel.c:10539
const ast_string_field name
Definition: app_queue.c:1696
Channel datastore data for max forwards.
Definition: max_forwards.c:29
void ast_party_connected_line_set(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src, const struct ast_set_party_connected_line *update)
Set the connected line information based on another connected line source.
Definition: channel.c:2054
static void setup_peer_after_bridge_goto(struct ast_channel *chan, struct ast_channel *peer, struct ast_flags *opts, char *opt_args[])
Definition: app_queue.c:6600
unsigned int reportholdtime
Definition: app_queue.c:1705
def info(msg)
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
struct ast_channel * chan
Definition: app_queue.c:6565
int errno
ast_channel_adsicpe
Definition: channel.h:869
int autofill
Definition: app_queue.c:1750
queue_reload_mask
Definition: app_queue.c:1398
static int extensionstate2devicestate(int state)
Helper function which converts from extension state to device state values.
Definition: app_queue.c:2590
static int queue_function_mem_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Get number either busy / free / ready or total members of a specific queue.
Definition: app_queue.c:8641
Connected Line/Party information.
Definition: channel.h:457
unsigned int pending_connected_update
Definition: app_queue.c:1547
int pbx_builtin_setvar_multiple(struct ast_channel *chan, const char *data)
Parse and set multiple channel variables, where the pairs are separated by the &#39;,&#39; character...
struct ast_party_dialed * ast_channel_dialed(struct ast_channel *chan)
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition: channel.c:7866
int talktime
Definition: app_queue.c:1727
const ast_string_field caller_uniqueid
Definition: app_queue.c:5965
char context[AST_MAX_CONTEXT]
#define EVENT_FLAG_AGENT
Definition: manager.h:76
struct local_optimization caller_optimize
Definition: app_queue.c:5985
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
Definition: app_queue.c:7528
struct call_queue::@69 list
time_t last_pos
Definition: app_queue.c:1574
#define AST_TRANSFERER_ROLE_NAME
Definition: bridge_basic.h:36
static int ql_exec(struct ast_channel *chan, const char *data)
QueueLog application.
Definition: app_queue.c:8106
Redirecting Line information. RDNIS (Redirecting Directory Number Information Service) Where a call d...
Definition: channel.h:523
#define LOG_NOTICE
Definition: logger.h:263
struct stasis_topic * ast_device_state_topic_all(void)
Get the Stasis topic for device state messages.
Definition: devicestate.c:668
static void update_status(struct call_queue *q, struct member *m, const int status)
set a member&#39;s status based on device state of that member&#39;s state_interface.
Definition: app_queue.c:2437
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:8793
int roundingseconds
Definition: app_queue.c:1725
static void set_queue_member_ringinuse(struct call_queue *q, struct member *mem, int ringinuse)
Definition: app_queue.c:7622
struct stasis_message_type * ast_attended_transfer_type(void)
Message type for ast_attended_transfer_message.
static void dump_queue_members(struct call_queue *pm_queue)
Dump all members in a specific queue to the database.
Definition: app_queue.c:7269
Definition: astdb.h:31
void ast_channel_publish_dial_forward(struct ast_channel *caller, struct ast_channel *peer, struct ast_channel *forwarded, const char *dialstring, const char *dialstatus, const char *forward)
Publish in the ast_channel_topic or ast_channel_topic_all topics a stasis message for the channels in...
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:409
static struct ast_manager_event_blob * queue_agent_dump_to_ami(struct stasis_message *message)
Definition: app_queue.c:2140
int stasis_subscription_final_message(struct stasis_subscription *sub, struct stasis_message *msg)
Determine whether a message is the final message to be received on a subscription.
Definition: stasis.c:1176
char reason_paused[80]
Definition: app_queue.c:1605
long int flag
Definition: f2c.h:83
static void device_state_cb(void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
set a member&#39;s status based on device state of that member&#39;s interface
Definition: app_queue.c:2503
static char * app_pqm
Definition: app_queue.c:1454
STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_caller_join_type,.to_ami=queue_caller_join_to_ami,)
int ast_channel_sendurl(struct ast_channel *channel, const char *url)
Sends a URL on a given link Send URL on link.
Definition: channel.c:6732
static struct call_queue * alloc_queue(const char *queuename)
Definition: app_queue.c:3534
struct ast_bridge_snapshot * bridge_snapshot
#define ast_channel_unlock(chan)
Definition: channel.h:2946
#define CLI_FAILURE
Definition: cli.h:46
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic&#39;s subscribers.
Definition: stasis.c:1511
#define AST_MAX_CONTEXT
Definition: channel.h:136
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Definition: lock.h:602
void ast_channel_inherit_variables(const struct ast_channel *parent, struct ast_channel *child)
Inherits channel variable from parent to child channel.
Definition: channel.c:6866
int source
Information about the source of an update.
Definition: channel.h:483
#define ast_free(a)
Definition: astmm.h:182
char * command
Definition: cli.h:186
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
int state_id
Definition: app_queue.c:1597
static char * complete_queue_remove_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:10639
#define AST_CHANNEL_NAME
Definition: channel.h:172
struct local_optimization member_optimize
Definition: app_queue.c:5987
const char * ast_term_reset(void)
Returns the terminal reset code.
Definition: term.c:306
static int queue_function_queuegetchannel(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Dialplan function QUEUE_GET_CHANNEL() Get caller channel waiting at specified position in the queue...
Definition: app_queue.c:8847
static int manager_change_priority_caller_on_queue(struct mansession *s, const struct message *m)
Definition: app_queue.c:10517
static int play_file(struct ast_channel *chan, const char *filename)
Definition: app_queue.c:3916
#define AST_FLAGS_ALL
Definition: utils.h:196
#define queues_t_link(c, q, tag)
Definition: app_queue.c:1922
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2548
struct penalty_rule::@68 list
static void to_ami(struct ast_sip_subscription *sub, struct ast_str **buf)
const ast_string_field moh
Definition: app_queue.c:1696
struct stasis_forward * stasis_forward_cancel(struct stasis_forward *forward)
Definition: stasis.c:1548
const char * word
Definition: cli.h:163
struct rule_list::@72 list
void * ast_aoc_destroy_encoded(struct ast_aoc_encoded *encoded)
free an ast_aoc_encoded object
Definition: aoc.c:313
const char * name
Definition: app_queue.c:1422
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
Definition: stasis.c:1136
static char * complete_queue_add_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:10426
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define DEFAULT_TIMEOUT
Definition: app_queue.c:1430
int stasis_message_router_set_default(struct stasis_message_router *router, stasis_subscription_cb callback, void *data)
Sets the default route of a router.
static int manager_queues_status(struct mansession *s, const struct message *m)
Queue status info via AMI.
Definition: app_queue.c:10104
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
const char * ast_term_color(int fgcolor, int bgcolor)
Return a color sequence string.
Definition: term.c:290
const ast_string_field uniqueid
Definition: bridge.h:336
int timeoutpriority
Definition: app_queue.c:1745
const ast_string_field defaultrule
Definition: app_queue.c:1696
An API for managing task processing threads that can be shared across modules.
const ast_string_field sound_seconds
Definition: app_queue.c:1696
Basic bridge subclass API.
void ast_autoservice_chan_hangup_peer(struct ast_channel *chan, struct ast_channel *peer)
Put chan into autoservice while hanging up peer.
Definition: autoservice.c:342
struct penalty_rule * pr
Definition: app_queue.c:1588
Structure used to handle boolean flags.
Definition: utils.h:199
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
Definition: manager.c:1720
static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
The waiting areas for callers who are not actively calling members.
Definition: app_queue.c:5626
unsigned int announceposition
Definition: app_queue.c:1709
struct ast_party_redirecting * ast_channel_redirecting(struct ast_channel *chan)
int pending
Definition: app_queue.c:1577
unsigned int found
Definition: app_queue.c:1713
static void queue_publish_multi_channel_blob(struct ast_channel *caller, struct ast_channel *agent, struct stasis_message_type *type, struct ast_json *blob)
Definition: app_queue.c:2201
static struct ast_manager_event_blob * queue_agent_called_to_ami(struct stasis_message *message)
Definition: app_queue.c:2125
static int manager_queues_summary(struct mansession *s, const struct message *m)
Summary of queue info via the AMI.
Definition: app_queue.c:10026
time_t starttime
Definition: app_queue.c:1609
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
const char * usage
Definition: cli.h:177
struct stasis_topic * ast_bridge_topic_all(void)
A topic which publishes the events for all bridges.
int randomperiodicannounce
Definition: app_queue.c:1724
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
struct ast_format_cap * ast_channel_nativeformats(const struct ast_channel *chan)
int calls
Definition: app_queue.c:1600
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
static int queue_function_queuememberlist(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Dialplan function QUEUE_MEMBER_LIST() Get list of members in a specific queue.
Definition: app_queue.c:8963
#define RES_NOSUCHQUEUE
Definition: app_queue.c:1444
#define ANNOUNCEHOLDTIME_ALWAYS
Definition: app_queue.c:1636
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3184
void(* end_bridge_callback)(void *)
Definition: channel.h:1091
int status
Definition: app_queue.c:1603
unsigned int setqueueentryvar
Definition: app_queue.c:1704
#define queue_t_unref(q, tag)
Definition: app_queue.c:1921
#define ast_channel_lock_both(chan1, chan2)
Lock two channels.
Definition: channel.h:2952
static struct ast_manager_event_blob * queue_member_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2020
static int available(struct dahdi_pvt **pvt, int is_specific_channel)
Definition: chan_dahdi.c:13058
static struct ast_cli_entry cli_queue[]
Definition: app_queue.c:11234
#define CLI_SUCCESS
Definition: cli.h:44
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:694
const ast_string_field announce
Definition: app_queue.c:1696
const ast_string_field sound_reporthold
Definition: app_queue.c:1696
static void callattempt_free(struct callattempt *doomed)
Definition: app_queue.c:4228
static int set_member_value_help_members(struct call_queue *q, const char *interface, int property, int value)
Definition: app_queue.c:7651
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:688
Assume that the ao2_container is already locked.
Definition: astobj2.h:1872
struct stasis_message_type * ast_local_optimization_begin_type(void)
Message type for when a local channel optimization begins.
int callsabandoned
Definition: app_queue.c:1729
The arg parameter is an object of the same type.
Definition: astobj2.h:1091
int transit_network_select
Transit Network Select.
Definition: channel.h:398
#define ANNOUNCEPOSITION_LIMIT
Definition: app_queue.c:1654
static int store_next_lin(struct queue_ent *qe, struct callattempt *outgoing)
Search for best metric and add to Linear queue.
Definition: app_queue.c:4723
void ast_party_redirecting_free(struct ast_party_redirecting *doomed)
Destroy the redirecting information contents.
Definition: channel.c:2179
void ast_party_connected_line_copy(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src)
Copy the source connected line information to the destination connected line.
Definition: channel.c:2031
char * strsep(char **str, const char *delims)
static void record_abandoned(struct queue_ent *qe)
Record that a caller gave up on waiting in queue.
Definition: app_queue.c:4808
int ast_max_forwards_decrement(struct ast_channel *chan)
Decrement the max forwards count for a particular channel.
Definition: max_forwards.c:135
static void send_agent_complete(const char *queuename, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const struct member *member, time_t holdstart, time_t callstart, enum agent_complete_reason rsn)
Send out AMI message with member call completion status information.
Definition: app_queue.c:5864
FILE * out
Definition: utils/frame.c:33
const ast_string_field sound_calls
Definition: app_queue.c:1696
After Bridge Execution API.
static int realtime_rules
queuesrules.conf [general] option
Definition: app_queue.c:1481
#define abs(x)
Definition: f2c.h:195
int numperiodicannounce
Definition: app_queue.c:1723
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object...
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
int ast_say_number(struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options)
says a number
Definition: channel.c:8337
Standard Command Line Interface.
static struct call_queue * find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
Reload a single queue via realtime.
Definition: app_queue.c:3558
time_t last_periodic_announce_time
Definition: app_queue.c:1572
void AST_OPTIONAL_API_NAME() ast_monitor_setjoinfiles(struct ast_channel *chan, int turnon)
Definition: res_monitor.c:926
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition: json.c:397
static struct ast_custom_function queuevar_function
Definition: app_queue.c:9084
int ast_channel_hangupcause(const struct ast_channel *chan)
int ast_db_del(const char *family, const char *key)
Delete entry in astdb.
Definition: main/db.c:429
static void queue_rules_reset_global_params(void)
Definition: app_queue.c:9122
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
void ast_connected_line_copy_from_caller(struct ast_party_connected_line *dest, const struct ast_party_caller *src)
Copy the caller information to the connected line information.
Definition: channel.c:8389
char rt_uniqueid[80]
Definition: app_queue.c:1615
int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
Uses hint and devicestate callback to get the state of an extension.
Definition: pbx.c:3170
static void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
Insert the &#39;new&#39; entry after the &#39;prev&#39; entry of queue &#39;q&#39;.
Definition: app_queue.c:1952
static int autopause2int(const char *autopause)
Definition: app_queue.c:1813
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
ast_app: A registered application
Definition: pbx_app.c:45
unsigned int realtime
Definition: app_queue.c:1712
const char * ast_channel_name(const struct ast_channel *chan)
void ast_party_redirecting_init(struct ast_party_redirecting *init)
Initialize the given redirecting structure.
Definition: channel.c:2122
static void handle_local_optimization_begin(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6281
static struct member * get_interface_helper(struct call_queue *q, const char *interface)
Definition: app_queue.c:8618
static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, int raise_penalty, enum empty_conditions conditions, int devstate)
Check if members are available.
Definition: app_queue.c:2284
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"...
Definition: main/utils.c:1968
static int compress_char(const char c)
Definition: app_queue.c:2730
struct ast_channel_snapshot * ast_multi_channel_blob_get_channel(struct ast_multi_channel_blob *obj, const char *role)
Retrieve a channel snapshot associated with a specific role from a ast_multi_channel_blob.
const int pos
Definition: cli.h:164
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1776
static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
Set variables of queue.
Definition: app_queue.c:1926
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:1086
queue_timeout_priority
Definition: app_queue.c:1520
Channel monitoring.
A multi channel blob data structure for multi_channel_blob stasis messages.
static int aqm_exec(struct ast_channel *chan, const char *data)
AddQueueMember application.
Definition: app_queue.c:8025
static void hangupcalls(struct queue_ent *qe, struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere)
Hang up a list of outgoing calls.
Definition: app_queue.c:4250
#define END_OPTIONS
void stasis_message_router_unsubscribe(struct stasis_message_router *router)
Unsubscribe the router from the upstream topic.
#define ast_frfree(fr)
User data for stasis subscriptions used for queue calls.
Definition: app_queue.c:5957
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition: ael_main.c:211
#define ao2_t_find(container, arg, flags, tag)
Definition: astobj2.h:1754
char state_context[AST_MAX_CONTEXT]
Definition: app_queue.c:1595
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
Definition: stasis.c:1025
struct stasis_forward * sub
Definition: res_corosync.c:240
Data structure associated with a single frame of data.
int ast_app_exec_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const char *sub_args, int ignore_hangup)
Run a subroutine on a channel, placing an optional second channel into autoservice.
Definition: main/app.c:370
Internal Asterisk hangup causes.
static int pending_members_cmp(void *obj, void *arg, int flags)
Definition: app_queue.c:2398
const char * ast_channel_language(const struct ast_channel *chan)
enum empty_conditions leavewhenempty
Definition: app_queue.c:1718
static int use_weight
Records that one or more queues use weight.
Definition: app_queue.c:1469
Abstract JSON element (object, array, string, int, ...).
struct queue_ent::@67 qe_rules
Definition: aoc.h:64
#define AST_OPTION_TONE_VERIFY
static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask, const char *queuename)
Reload information pertaining to a particular queue.
Definition: app_queue.c:9383
#define RES_EXISTS
Definition: app_queue.c:1442
The structure that contains device state.
Definition: devicestate.h:240
static struct ast_manager_event_blob * queue_agent_ringnoanswer_to_ami(struct stasis_message *message)
Definition: app_queue.c:2145
loadable MixMonitor functionality
Definition: search.h:40
const char * ast_channel_context(const struct ast_channel *chan)
Handy terminal functions for vt* terms.
int ast_db_put(const char *family, const char *key, const char *value)
Store value addressed by family/key.
Definition: main/db.c:327
Forwarding information.
Definition: stasis.c:1531
static void print_queue(struct mansession *s, int fd, struct call_queue *q)
Print a single queue to AMI or the CLI.
Definition: app_queue.c:9654
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Definition: astobj2.h:1358
void ast_bridge_set_after_go_on(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *parseable_goto)
Set channel to go on in the dialplan after the bridge.
Definition: bridge_after.c:636
struct queue_ent * next
Definition: app_queue.c:1589
enum ast_aoc_type ast_aoc_get_msg_type(struct ast_aoc_decoded *decoded)
get the message type, AOC-D, AOC-E, or AOC Request
Definition: aoc.c:892
unsigned int relativeperiodicannounce
Definition: app_queue.c:1714
static int get_queue_member_status(struct member *cur)
Return the current state of a member.
Definition: app_queue.c:2671
union ast_frame::@263 data
enum queue_result id
Definition: app_queue.c:1507
static int publish_queue_member_pause(struct call_queue *q, struct member *member)
Definition: app_queue.c:7457
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
enum ast_frame_type frametype
#define PATH_MAX
Definition: asterisk.h:40
static const char *const pm_family
Persistent Members astdb family.
Definition: app_queue.c:1463
static int queue_exec(struct ast_channel *chan, const char *data)
The starting point for all queue calls.
Definition: app_queue.c:8183
#define RECHECK
Definition: app_queue.c:1431
static void reload_queue_members(void)
Reload dynamic queue members persisted into the astdb.
Definition: app_queue.c:7771
static void queue_agent_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:5895
const ast_string_field sound_minutes
Definition: app_queue.c:1696
static void remove_stasis_subscriptions(struct queue_stasis_data *queue_data)
Definition: app_queue.c:6011
static int queue_hash_cb(const void *obj, const int flags)
Definition: app_queue.c:1836
char context[AST_MAX_CONTEXT]
Definition: app_queue.c:1564
Generic container type.
static void do_hang(struct callattempt *o)
common hangup actions
Definition: app_queue.c:4358
struct callattempt * call_next
Definition: app_queue.c:1539
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:280
static int manager_add_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10222
static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_args, char *announceoverride, const char *url, int *tries, int *noption, const char *agi, const char *macro, const char *gosub, int ringing)
Definition: app_queue.c:6722
static struct test_options options
const ast_string_field queue_quantity2
Definition: app_queue.c:1696
Search option field mask.
Definition: astobj2.h:1076
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
static void init_queue(struct call_queue *q)
Initialize Queue default values.
Definition: app_queue.c:2769
Call Parking and Pickup API Includes code and algorithms from the Zapata library. ...
int handled
Definition: app_queue.c:1576
int cancel_answered_elsewhere
Definition: app_queue.c:1585
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
#define ANNOUNCEHOLDTIME_ONCE
Definition: app_queue.c:1637
#define AST_LIST_INSERT_BEFORE_CURRENT(elm, field)
Inserts a list entry before the current entry during a traversal.
Definition: linkedlists.h:598
static int queue_function_queuewaitingcount(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Dialplan function QUEUE_WAITING_COUNT() Get number callers waiting in a specific queue.
Definition: app_queue.c:8926
struct stasis_forward * stasis_forward_all(struct stasis_topic *from_topic, struct stasis_topic *to_topic)
Create a subscription which forwards all messages from one topic to another.
Definition: stasis.c:1578
int ast_extension_state_add(const char *context, const char *exten, ast_state_cb_type change_cb, void *data)
Add watcher for extension states.
Definition: pbx.c:3825
static int remove_from_queue(const char *queuename, const char *interface)
Remove member from queue.
Definition: app_queue.c:7324
static int set_member_value(const char *queuename, const char *interface, int property, int value)
Definition: app_queue.c:7674
struct stasis_topic * ast_queue_topic(const char *queuename)
Get the Stasis Message Bus API topic for queue messages for a particular queue name.
Definition: main/app.c:3189
static char * handle_queue_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:11051
unsigned int ringinuse
Definition: app_queue.c:1616
static void copy_rules(struct queue_ent *qe, const char *rulename)
Copy rule from global list into specified queue.
Definition: app_queue.c:8140
static char url[512]
static void queue_member_follower_removal(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:1905
static struct queue_stasis_data * queue_stasis_data_alloc(struct queue_ent *qe, struct ast_channel *peer, struct member *mem, time_t holdstart, time_t starttime, int callcompletedinsl)
Definition: app_queue.c:6026
struct ast_app * pbx_findapp(const char *app)
Look up an application.
Definition: ael_main.c:165
struct stasis_message_type * ast_channel_hangup_request_type(void)
Message type for when a hangup is requested on a channel.
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:186
static void update_qe_rule(struct queue_ent *qe)
update rules for queues
Definition: app_queue.c:5536
Say numbers and dates (maybe words one day too)
static const struct autopause autopausesmodes[]
int callcompletedinsl
Definition: app_queue.c:1607
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
unsigned int dial_callerid_absent
Definition: app_queue.c:1551
enum empty_conditions joinempty
Definition: app_queue.c:1717
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
static char * handle_queue_set_member_penalty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:10953
#define RESULT_SUCCESS
Definition: cli.h:40
struct ast_channel * chan
Definition: app_queue.c:1540
const ast_string_field queue_quantity1
Definition: app_queue.c:1696
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3159
char connected
Definition: eagi_proxy.c:82
Asterisk module definitions.
#define COLOR_BROWN
Definition: term.h:53
static int manager_pause_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10333
static void setup_mixmonitor(struct queue_ent *qe, const char *filename)
Definition: app_queue.c:6648
static int is_our_turn(struct queue_ent *qe)
Check if we should start attempting to call queue members.
Definition: app_queue.c:5487
#define queues_t_unlink(c, q, tag)
Definition: app_queue.c:1923
intmax_t ast_json_integer_get(const struct ast_json *integer)
Get the value from a JSON integer.
Definition: json.c:322
struct stasis_message_type * ast_channel_masquerade_type(void)
Message type for when a channel is being masqueraded.
static struct stasis_subscription * device_state_sub
Subscription to device state change messages.
Definition: app_queue.c:1484
static struct ast_manager_event_blob * queue_agent_connect_to_ami(struct stasis_message *message)
Definition: app_queue.c:2130
static int kill_if_unfound(void *obj, void *arg, int flags)
Definition: app_queue.c:9516
int callscompleted
Definition: app_queue.c:1728
static int valid_exit(struct queue_ent *qe, char digit)
Check for valid exit from queue via goto.
Definition: app_queue.c:3945
static int shared_lastcall
queues.conf [general] option
Definition: app_queue.c:1478
Persistant data storage (akin to *doze registry)
static char * handle_queue_pause_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:10818
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:368
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
struct call_queue::@70 rules
const ast_string_field sound_callerannounce
Definition: app_queue.c:1696
int announcefrequency
Definition: app_queue.c:1720
AO2_STRING_FIELD_SORT_FN(call_queue, name)
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:298
enum ast_transfer_result result
const struct ast_channel_tech * ast_channel_tech(const struct ast_channel *chan)
static char * app_upqm
Definition: app_queue.c:1456
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
static int set_member_penalty_help_members(struct call_queue *q, const char *interface, int penalty)
Definition: app_queue.c:7584
static int manager_remove_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10286
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1508
time_t lastcall
Definition: app_queue.c:1610
unsigned int stillgoing
Definition: app_queue.c:1553
const char * ast_channel_macroexten(const struct ast_channel *chan)
char announce[PATH_MAX]
Definition: app_queue.c:1563
static const char * int2strat(int strategy)
Definition: app_queue.c:1787
void ast_channel_data_set(struct ast_channel *chan, const char *value)
static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface, const char *reason_paused, int wrapuptime)
Add member to queue.
Definition: app_queue.c:7377
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:187
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626
static int queue_persistent_members
queues.conf [general] option
Definition: app_queue.c:1466
static int reload_queues(int reload, struct ast_flags *mask, const char *queuename)
reload the queues.conf file
Definition: app_queue.c:9540
struct ast_multi_channel_blob * ast_multi_channel_blob_create(struct ast_json *blob)
Create a ast_multi_channel_blob suitable for a stasis_message.
void ast_party_redirecting_copy(struct ast_party_redirecting *dest, const struct ast_party_redirecting *src)
Copy the source redirecting information to the destination redirecting.
Definition: channel.c:2135
static char * complete_queue_show(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:9966
#define RESULT_FAILURE
Definition: cli.h:42
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
Definition: strings.h:1250
static int clear_stats(const char *queuename)
Facilitates resetting statistics for a queue.
Definition: app_queue.c:9597
static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
Place a call to a queue member.
Definition: app_queue.c:4639
static void queue_publish_member_blob(struct stasis_message_type *type, struct ast_json *blob)
Definition: app_queue.c:2234
jack_status_t status
Definition: app_jack.c:146
char state_exten[AST_MAX_EXTENSION]
Definition: app_queue.c:1594
#define COLOR_MAGENTA
Definition: term.h:57
const ast_string_field name
int ast_channel_redirecting_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *redirecting_info, int is_caller, int is_frame)
Run a redirecting interception macro and update a channel&#39;s redirecting information.
Definition: channel.c:10487
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620
short word
char * key
Definition: astdb.h:33
#define AST_APP_ARG(name)
Define an application argument.
int strategy
Definition: app_queue.c:1406
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:514
static int load_realtime_rules(void)
Load queue rules from realtime.
Definition: app_queue.c:2999
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition: manager.c:3201
static struct test_val a
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:343
#define ao2_link(container, obj)
Definition: astobj2.h:1549
static int is_member_available(struct call_queue *q, struct member *mem)
Definition: app_queue.c:2468
const char * name
Definition: app_queue.c:1407
static void set_queue_member_pause(struct call_queue *q, struct member *mem, const char *reason, int paused)
Definition: app_queue.c:7483