Wed Jan 8 2020 09:49:40

Asterisk developer's documentation


app_queue.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*! \file
20  *
21  * \brief True call queues with optional send URL on answer
22  *
23  * \author Mark Spencer <markster@digium.com>
24  *
25  * \arg Config in \ref Config_qu queues.conf
26  *
27  * \par Development notes
28  * \note 2004-11-25: Persistent Dynamic Members added by:
29  * NetNation Communications (www.netnation.com)
30  * Kevin Lindsay <kevinl@netnation.com>
31  *
32  * Each dynamic agent in each queue is now stored in the astdb.
33  * When asterisk is restarted, each agent will be automatically
34  * readded into their recorded queues. This feature can be
35  * configured with the 'persistent_members=<1|0>' setting in the
36  * '[general]' category in queues.conf. The default is on.
37  *
38  * \note 2004-06-04: Priorities in queues added by inAccess Networks (work funded by Hellas On Line (HOL) www.hol.gr).
39  *
40  * \note These features added by David C. Troy <dave@toad.net>:
41  * - Per-queue holdtime calculation
42  * - Estimated holdtime announcement
43  * - Position announcement
44  * - Abandoned/completed call counters
45  * - Failout timer passed as optional app parameter
46  * - Optional monitoring of calls, started when call is answered
47  *
48  * Patch Version 1.07 2003-12-24 01
49  *
50  * Added servicelevel statistic by Michiel Betel <michiel@betel.nl>
51  * Added Priority jumping code for adding and removing queue members by Jonathan Stanton <asterisk@doilooklikeicare.com>
52  *
53  * Fixed to work with CVS as of 2004-02-25 and released as 1.07a
54  * by Matthew Enger <m.enger@xi.com.au>
55  *
56  * \ingroup applications
57  */
58 
59 /*** MODULEINFO
60  <use>res_monitor</use>
61  <support_level>core</support_level>
62  ***/
63 
64 #include "asterisk.h"
65 
66 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419684 $")
67 
68 #include <sys/time.h>
69 #include <sys/signal.h>
70 #include <netinet/in.h>
71 #include <ctype.h>
72 
73 #include "asterisk/lock.h"
74 #include "asterisk/file.h"
75 #include "asterisk/channel.h"
76 #include "asterisk/pbx.h"
77 #include "asterisk/app.h"
78 #include "asterisk/linkedlists.h"
79 #include "asterisk/module.h"
80 #include "asterisk/translate.h"
81 #include "asterisk/say.h"
82 #include "asterisk/features.h"
83 #include "asterisk/musiconhold.h"
84 #include "asterisk/cli.h"
85 #include "asterisk/manager.h"
86 #include "asterisk/config.h"
87 #include "asterisk/monitor.h"
88 #include "asterisk/utils.h"
89 #include "asterisk/causes.h"
90 #include "asterisk/astdb.h"
91 #include "asterisk/devicestate.h"
92 #include "asterisk/stringfields.h"
93 #include "asterisk/event.h"
94 #include "asterisk/astobj2.h"
95 #include "asterisk/strings.h"
97 #include "asterisk/taskprocessor.h"
98 #include "asterisk/aoc.h"
99 #include "asterisk/callerid.h"
100 #include "asterisk/cel.h"
101 #include "asterisk/data.h"
102 
103 /* Define, to debug reference counts on queues, without debugging reference counts on queue members */
104 /* #define REF_DEBUG_ONLY_QUEUES */
105 
106 /*!
107  * \par Please read before modifying this file.
108  * There are three locks which are regularly used
109  * throughout this file, the queue list lock, the lock
110  * for each individual queue, and the interface list lock.
111  * Please be extra careful to always lock in the following order
112  * 1) queue list lock
113  * 2) individual queue lock
114  * 3) interface list lock
115  * This order has sort of "evolved" over the lifetime of this
116  * application, but it is now in place this way, so please adhere
117  * to this order!
118  */
119 
120 /*** DOCUMENTATION
121  <application name="Queue" language="en_US">
122  <synopsis>
123  Queue a call for a call queue.
124  </synopsis>
125  <syntax>
126  <parameter name="queuename" required="true" />
127  <parameter name="options">
128  <optionlist>
129  <option name="C">
130  <para>Mark all calls as "answered elsewhere" when cancelled.</para>
131  </option>
132  <option name="c">
133  <para>Continue in the dialplan if the callee hangs up.</para>
134  </option>
135  <option name="d">
136  <para>data-quality (modem) call (minimum delay).</para>
137  </option>
138  <option name="h">
139  <para>Allow <emphasis>callee</emphasis> to hang up by pressing <literal>*</literal>.</para>
140  </option>
141  <option name="H">
142  <para>Allow <emphasis>caller</emphasis> to hang up by pressing <literal>*</literal>.</para>
143  </option>
144  <option name="n">
145  <para>No retries on the timeout; will exit this application and
146  go to the next step.</para>
147  </option>
148  <option name="i">
149  <para>Ignore call forward requests from queue members and do nothing
150  when they are requested.</para>
151  </option>
152  <option name="I">
153  <para>Asterisk will ignore any connected line update requests or any redirecting party
154  update requests it may receive on this dial attempt.</para>
155  </option>
156  <option name="r">
157  <para>Ring instead of playing MOH. Periodic Announcements are still made, if applicable.</para>
158  </option>
159  <option name="R">
160  <para>Ring instead of playing MOH when a member channel is actually ringing.</para>
161  </option>
162  <option name="t">
163  <para>Allow the <emphasis>called</emphasis> user to transfer the calling user.</para>
164  </option>
165  <option name="T">
166  <para>Allow the <emphasis>calling</emphasis> user to transfer the call.</para>
167  </option>
168  <option name="w">
169  <para>Allow the <emphasis>called</emphasis> user to write the conversation to
170  disk via Monitor.</para>
171  </option>
172  <option name="W">
173  <para>Allow the <emphasis>calling</emphasis> user to write the conversation to
174  disk via Monitor.</para>
175  </option>
176  <option name="k">
177  <para>Allow the <emphasis>called</emphasis> party to enable parking of the call by sending
178  the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
179  </option>
180  <option name="K">
181  <para>Allow the <emphasis>calling</emphasis> party to enable parking of the call by sending
182  the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
183  </option>
184  <option name="x">
185  <para>Allow the <emphasis>called</emphasis> user to write the conversation
186  to disk via MixMonitor.</para>
187  </option>
188  <option name="X">
189  <para>Allow the <emphasis>calling</emphasis> user to write the conversation to
190  disk via MixMonitor.</para>
191  </option>
192  </optionlist>
193  </parameter>
194  <parameter name="URL">
195  <para><replaceable>URL</replaceable> will be sent to the called party if the channel supports it.</para>
196  </parameter>
197  <parameter name="announceoverride" />
198  <parameter name="timeout">
199  <para>Will cause the queue to fail out after a specified number of
200  seconds, checked between each <filename>queues.conf</filename> <replaceable>timeout</replaceable> and
201  <replaceable>retry</replaceable> cycle.</para>
202  </parameter>
203  <parameter name="AGI">
204  <para>Will setup an AGI script to be executed on the calling party's channel once they are
205  connected to a queue member.</para>
206  </parameter>
207  <parameter name="macro">
208  <para>Will run a macro on the called party's channel (the queue member) once the parties are connected.</para>
209  </parameter>
210  <parameter name="gosub">
211  <para>Will run a gosub on the called party's channel (the queue member) once the parties are connected.</para>
212  </parameter>
213  <parameter name="rule">
214  <para>Will cause the queue's defaultrule to be overridden by the rule specified.</para>
215  </parameter>
216  <parameter name="position">
217  <para>Attempt to enter the caller into the queue at the numerical position specified. <literal>1</literal>
218  would attempt to enter the caller at the head of the queue, and <literal>3</literal> would attempt to place
219  the caller third in the queue.</para>
220  </parameter>
221  </syntax>
222  <description>
223  <para>In addition to transferring the call, a call may be parked and then picked
224  up by another user.</para>
225  <para>This application will return to the dialplan if the queue does not exist, or
226  any of the join options cause the caller to not enter the queue.</para>
227  <para>This application does not automatically answer and should be preceeded
228  by an application such as Answer(), Progress(), or Ringing().</para>
229  <para>This application sets the following channel variable upon completion:</para>
230  <variablelist>
231  <variable name="QUEUESTATUS">
232  <para>The status of the call as a text string.</para>
233  <value name="TIMEOUT" />
234  <value name="FULL" />
235  <value name="JOINEMPTY" />
236  <value name="LEAVEEMPTY" />
237  <value name="JOINUNAVAIL" />
238  <value name="LEAVEUNAVAIL" />
239  <value name="CONTINUE" />
240  </variable>
241  </variablelist>
242  </description>
243  <see-also>
244  <ref type="application">Queue</ref>
245  <ref type="application">QueueLog</ref>
246  <ref type="application">AddQueueMember</ref>
247  <ref type="application">RemoveQueueMember</ref>
248  <ref type="application">PauseQueueMember</ref>
249  <ref type="application">UnpauseQueueMember</ref>
250  <ref type="function">QUEUE_VARIABLES</ref>
251  <ref type="function">QUEUE_MEMBER</ref>
252  <ref type="function">QUEUE_MEMBER_COUNT</ref>
253  <ref type="function">QUEUE_EXISTS</ref>
254  <ref type="function">QUEUE_WAITING_COUNT</ref>
255  <ref type="function">QUEUE_MEMBER_LIST</ref>
256  <ref type="function">QUEUE_MEMBER_PENALTY</ref>
257  <ref type="function">QUEUE_MEMBER_STATUS</ref>
258  <ref type="function">QUEUE_MEMBER_PAUSED</ref>
259  </see-also>
260  </application>
261  <application name="AddQueueMember" language="en_US">
262  <synopsis>
263  Dynamically adds queue members.
264  </synopsis>
265  <syntax>
266  <parameter name="queuename" required="true" />
267  <parameter name="interface" />
268  <parameter name="penalty" />
269  <parameter name="options" />
270  <parameter name="membername" />
271  <parameter name="stateinterface" />
272  </syntax>
273  <description>
274  <para>Dynamically adds interface to an existing queue. If the interface is
275  already in the queue it will return an error.</para>
276  <para>This application sets the following channel variable upon completion:</para>
277  <variablelist>
278  <variable name="AQMSTATUS">
279  <para>The status of the attempt to add a queue member as a text string.</para>
280  <value name="ADDED" />
281  <value name="MEMBERALREADY" />
282  <value name="NOSUCHQUEUE" />
283  </variable>
284  </variablelist>
285  </description>
286  <see-also>
287  <ref type="application">Queue</ref>
288  <ref type="application">QueueLog</ref>
289  <ref type="application">AddQueueMember</ref>
290  <ref type="application">RemoveQueueMember</ref>
291  <ref type="application">PauseQueueMember</ref>
292  <ref type="application">UnpauseQueueMember</ref>
293  <ref type="function">QUEUE_VARIABLES</ref>
294  <ref type="function">QUEUE_MEMBER</ref>
295  <ref type="function">QUEUE_MEMBER_COUNT</ref>
296  <ref type="function">QUEUE_EXISTS</ref>
297  <ref type="function">QUEUE_WAITING_COUNT</ref>
298  <ref type="function">QUEUE_MEMBER_LIST</ref>
299  <ref type="function">QUEUE_MEMBER_PENALTY</ref>
300  <ref type="function">QUEUE_MEMBER_STATUS</ref>
301  <ref type="function">QUEUE_MEMBER_PAUSED</ref>
302  </see-also>
303  </application>
304  <application name="RemoveQueueMember" language="en_US">
305  <synopsis>
306  Dynamically removes queue members.
307  </synopsis>
308  <syntax>
309  <parameter name="queuename" required="true" />
310  <parameter name="interface" />
311  </syntax>
312  <description>
313  <para>If the interface is <emphasis>NOT</emphasis> in the queue it will return an error.</para>
314  <para>This application sets the following channel variable upon completion:</para>
315  <variablelist>
316  <variable name="RQMSTATUS">
317  <value name="REMOVED" />
318  <value name="NOTINQUEUE" />
319  <value name="NOSUCHQUEUE" />
320  <value name="NOTDYNAMIC" />
321  </variable>
322  </variablelist>
323  <para>Example: RemoveQueueMember(techsupport,SIP/3000)</para>
324  </description>
325  <see-also>
326  <ref type="application">Queue</ref>
327  <ref type="application">QueueLog</ref>
328  <ref type="application">AddQueueMember</ref>
329  <ref type="application">RemoveQueueMember</ref>
330  <ref type="application">PauseQueueMember</ref>
331  <ref type="application">UnpauseQueueMember</ref>
332  <ref type="function">QUEUE_VARIABLES</ref>
333  <ref type="function">QUEUE_MEMBER</ref>
334  <ref type="function">QUEUE_MEMBER_COUNT</ref>
335  <ref type="function">QUEUE_EXISTS</ref>
336  <ref type="function">QUEUE_WAITING_COUNT</ref>
337  <ref type="function">QUEUE_MEMBER_LIST</ref>
338  <ref type="function">QUEUE_MEMBER_PENALTY</ref>
339  <ref type="function">QUEUE_MEMBER_STATUS</ref>
340  <ref type="function">QUEUE_MEMBER_PAUSED</ref>
341  </see-also>
342  </application>
343  <application name="PauseQueueMember" language="en_US">
344  <synopsis>
345  Pauses a queue member.
346  </synopsis>
347  <syntax>
348  <parameter name="queuename" />
349  <parameter name="interface" required="true" />
350  <parameter name="options" />
351  <parameter name="reason">
352  <para>Is used to add extra information to the appropriate queue_log entries and manager events.</para>
353  </parameter>
354  </syntax>
355  <description>
356  <para>Pauses (blocks calls for) a queue member. The given interface will be paused in the given queue.
357  This prevents any calls from being sent from the queue to the interface until it is
358  unpaused with UnpauseQueueMember or the manager interface. If no queuename is given,
359  the interface is paused in every queue it is a member of. The application will fail if the
360  interface is not found.</para>
361  <para>This application sets the following channel variable upon completion:</para>
362  <variablelist>
363  <variable name="PQMSTATUS">
364  <para>The status of the attempt to pause a queue member as a text string.</para>
365  <value name="PAUSED" />
366  <value name="NOTFOUND" />
367  </variable>
368  </variablelist>
369  <para>Example: PauseQueueMember(,SIP/3000)</para>
370  </description>
371  <see-also>
372  <ref type="application">Queue</ref>
373  <ref type="application">QueueLog</ref>
374  <ref type="application">AddQueueMember</ref>
375  <ref type="application">RemoveQueueMember</ref>
376  <ref type="application">PauseQueueMember</ref>
377  <ref type="application">UnpauseQueueMember</ref>
378  <ref type="function">QUEUE_VARIABLES</ref>
379  <ref type="function">QUEUE_MEMBER</ref>
380  <ref type="function">QUEUE_MEMBER_COUNT</ref>
381  <ref type="function">QUEUE_EXISTS</ref>
382  <ref type="function">QUEUE_WAITING_COUNT</ref>
383  <ref type="function">QUEUE_MEMBER_LIST</ref>
384  <ref type="function">QUEUE_MEMBER_PENALTY</ref>
385  <ref type="function">QUEUE_MEMBER_STATUS</ref>
386  <ref type="function">QUEUE_MEMBER_PAUSED</ref>
387  </see-also>
388  </application>
389  <application name="UnpauseQueueMember" language="en_US">
390  <synopsis>
391  Unpauses a queue member.
392  </synopsis>
393  <syntax>
394  <parameter name="queuename" />
395  <parameter name="interface" required="true" />
396  <parameter name="options" />
397  <parameter name="reason">
398  <para>Is used to add extra information to the appropriate queue_log entries and manager events.</para>
399  </parameter>
400  </syntax>
401  <description>
402  <para>Unpauses (resumes calls to) a queue member. This is the counterpart to <literal>PauseQueueMember()</literal>
403  and operates exactly the same way, except it unpauses instead of pausing the given interface.</para>
404  <para>This application sets the following channel variable upon completion:</para>
405  <variablelist>
406  <variable name="UPQMSTATUS">
407  <para>The status of the attempt to unpause a queue member as a text string.</para>
408  <value name="UNPAUSED" />
409  <value name="NOTFOUND" />
410  </variable>
411  </variablelist>
412  <para>Example: UnpauseQueueMember(,SIP/3000)</para>
413  </description>
414  <see-also>
415  <ref type="application">Queue</ref>
416  <ref type="application">QueueLog</ref>
417  <ref type="application">AddQueueMember</ref>
418  <ref type="application">RemoveQueueMember</ref>
419  <ref type="application">PauseQueueMember</ref>
420  <ref type="application">UnpauseQueueMember</ref>
421  <ref type="function">QUEUE_VARIABLES</ref>
422  <ref type="function">QUEUE_MEMBER</ref>
423  <ref type="function">QUEUE_MEMBER_COUNT</ref>
424  <ref type="function">QUEUE_EXISTS</ref>
425  <ref type="function">QUEUE_WAITING_COUNT</ref>
426  <ref type="function">QUEUE_MEMBER_LIST</ref>
427  <ref type="function">QUEUE_MEMBER_PENALTY</ref>
428  <ref type="function">QUEUE_MEMBER_STATUS</ref>
429  <ref type="function">QUEUE_MEMBER_PAUSED</ref>
430  </see-also>
431  </application>
432  <application name="QueueLog" language="en_US">
433  <synopsis>
434  Writes to the queue_log file.
435  </synopsis>
436  <syntax>
437  <parameter name="queuename" required="true" />
438  <parameter name="uniqueid" required="true" />
439  <parameter name="agent" required="true" />
440  <parameter name="event" required="true" />
441  <parameter name="additionalinfo" />
442  </syntax>
443  <description>
444  <para>Allows you to write your own events into the queue log.</para>
445  <para>Example: QueueLog(101,${UNIQUEID},${AGENT},WENTONBREAK,600)</para>
446  </description>
447  <see-also>
448  <ref type="application">Queue</ref>
449  <ref type="application">QueueLog</ref>
450  <ref type="application">AddQueueMember</ref>
451  <ref type="application">RemoveQueueMember</ref>
452  <ref type="application">PauseQueueMember</ref>
453  <ref type="application">UnpauseQueueMember</ref>
454  <ref type="function">QUEUE_VARIABLES</ref>
455  <ref type="function">QUEUE_MEMBER</ref>
456  <ref type="function">QUEUE_MEMBER_COUNT</ref>
457  <ref type="function">QUEUE_EXISTS</ref>
458  <ref type="function">QUEUE_WAITING_COUNT</ref>
459  <ref type="function">QUEUE_MEMBER_LIST</ref>
460  <ref type="function">QUEUE_MEMBER_PENALTY</ref>
461  <ref type="function">QUEUE_MEMBER_STATUS</ref>
462  <ref type="function">QUEUE_MEMBER_PAUSED</ref>
463  </see-also>
464  </application>
465  <function name="QUEUE_VARIABLES" language="en_US">
466  <synopsis>
467  Return Queue information in variables.
468  </synopsis>
469  <syntax>
470  <parameter name="queuename" required="true">
471  <enumlist>
472  <enum name="QUEUEMAX">
473  <para>Maxmimum number of calls allowed.</para>
474  </enum>
475  <enum name="QUEUESTRATEGY">
476  <para>The strategy of the queue.</para>
477  </enum>
478  <enum name="QUEUECALLS">
479  <para>Number of calls currently in the queue.</para>
480  </enum>
481  <enum name="QUEUEHOLDTIME">
482  <para>Current average hold time.</para>
483  </enum>
484  <enum name="QUEUECOMPLETED">
485  <para>Number of completed calls for the queue.</para>
486  </enum>
487  <enum name="QUEUEABANDONED">
488  <para>Number of abandoned calls.</para>
489  </enum>
490  <enum name="QUEUESRVLEVEL">
491  <para>Queue service level.</para>
492  </enum>
493  <enum name="QUEUESRVLEVELPERF">
494  <para>Current service level performance.</para>
495  </enum>
496  </enumlist>
497  </parameter>
498  </syntax>
499  <description>
500  <para>Makes the following queue variables available.</para>
501  <para>Returns <literal>0</literal> if queue is found and setqueuevar is defined, <literal>-1</literal> otherwise.</para>
502  </description>
503  <see-also>
504  <ref type="application">Queue</ref>
505  <ref type="application">QueueLog</ref>
506  <ref type="application">AddQueueMember</ref>
507  <ref type="application">RemoveQueueMember</ref>
508  <ref type="application">PauseQueueMember</ref>
509  <ref type="application">UnpauseQueueMember</ref>
510  <ref type="function">QUEUE_VARIABLES</ref>
511  <ref type="function">QUEUE_MEMBER</ref>
512  <ref type="function">QUEUE_MEMBER_COUNT</ref>
513  <ref type="function">QUEUE_EXISTS</ref>
514  <ref type="function">QUEUE_WAITING_COUNT</ref>
515  <ref type="function">QUEUE_MEMBER_LIST</ref>
516  <ref type="function">QUEUE_MEMBER_PENALTY</ref>
517  <ref type="function">QUEUE_MEMBER_STATUS</ref>
518  <ref type="function">QUEUE_MEMBER_PAUSED</ref>
519  </see-also>
520  </function>
521  <function name="QUEUE_MEMBER" language="en_US">
522  <synopsis>
523  Count number of members answering a queue.
524  </synopsis>
525  <syntax>
526  <parameter name="queuename" required="true" />
527  <parameter name="option" required="true">
528  <enumlist>
529  <enum name="logged">
530  <para>Returns the number of logged-in members for the specified queue.</para>
531  </enum>
532  <enum name="free">
533  <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>
534  </enum>
535  <enum name="ready">
536  <para>Returns the number of logged-in members for the specified queue that are immediately available to answer a call.</para>
537  </enum>
538  <enum name="paused">
539  <para>Returns the number of paused members for the specified queue.</para>
540  </enum>
541  <enum name="count">
542  <para>Returns the total number of members for the specified queue.</para>
543  </enum>
544  </enumlist>
545  </parameter>
546  </syntax>
547  <description>
548  <para>Returns the number of members currently associated with the specified <replaceable>queuename</replaceable>.</para>
549  </description>
550  <see-also>
551  <ref type="application">Queue</ref>
552  <ref type="application">QueueLog</ref>
553  <ref type="application">AddQueueMember</ref>
554  <ref type="application">RemoveQueueMember</ref>
555  <ref type="application">PauseQueueMember</ref>
556  <ref type="application">UnpauseQueueMember</ref>
557  <ref type="function">QUEUE_VARIABLES</ref>
558  <ref type="function">QUEUE_MEMBER</ref>
559  <ref type="function">QUEUE_MEMBER_COUNT</ref>
560  <ref type="function">QUEUE_EXISTS</ref>
561  <ref type="function">QUEUE_WAITING_COUNT</ref>
562  <ref type="function">QUEUE_MEMBER_LIST</ref>
563  <ref type="function">QUEUE_MEMBER_PENALTY</ref>
564  <ref type="function">QUEUE_MEMBER_STATUS</ref>
565  <ref type="function">QUEUE_MEMBER_PAUSED</ref>
566  </see-also>
567  </function>
568  <function name="QUEUE_MEMBER_COUNT" language="en_US">
569  <synopsis>
570  Count number of members answering a queue.
571  </synopsis>
572  <syntax>
573  <parameter name="queuename" required="true" />
574  </syntax>
575  <description>
576  <para>Returns the number of members currently associated with the specified <replaceable>queuename</replaceable>.</para>
577  <warning><para>This function has been deprecated in favor of the <literal>QUEUE_MEMBER()</literal> function</para></warning>
578  </description>
579  <see-also>
580  <ref type="application">Queue</ref>
581  <ref type="application">QueueLog</ref>
582  <ref type="application">AddQueueMember</ref>
583  <ref type="application">RemoveQueueMember</ref>
584  <ref type="application">PauseQueueMember</ref>
585  <ref type="application">UnpauseQueueMember</ref>
586  <ref type="function">QUEUE_VARIABLES</ref>
587  <ref type="function">QUEUE_MEMBER</ref>
588  <ref type="function">QUEUE_MEMBER_COUNT</ref>
589  <ref type="function">QUEUE_EXISTS</ref>
590  <ref type="function">QUEUE_WAITING_COUNT</ref>
591  <ref type="function">QUEUE_MEMBER_LIST</ref>
592  <ref type="function">QUEUE_MEMBER_PENALTY</ref>
593  <ref type="function">QUEUE_MEMBER_STATUS</ref>
594  <ref type="function">QUEUE_MEMBER_PAUSED</ref>
595  </see-also>
596  </function>
597  <function name="QUEUE_EXISTS" language="en_US">
598  <synopsis>
599  Check if a named queue exists on this server
600  </synopsis>
601  <syntax>
602  <parameter name="queuename" />
603  </syntax>
604  <description>
605  <para>Returns 1 if the specified queue exists, 0 if it does not</para>
606  </description>
607  <see-also>
608  <ref type="application">Queue</ref>
609  <ref type="application">QueueLog</ref>
610  <ref type="application">AddQueueMember</ref>
611  <ref type="application">RemoveQueueMember</ref>
612  <ref type="application">PauseQueueMember</ref>
613  <ref type="application">UnpauseQueueMember</ref>
614  <ref type="function">QUEUE_VARIABLES</ref>
615  <ref type="function">QUEUE_MEMBER</ref>
616  <ref type="function">QUEUE_MEMBER_COUNT</ref>
617  <ref type="function">QUEUE_EXISTS</ref>
618  <ref type="function">QUEUE_WAITING_COUNT</ref>
619  <ref type="function">QUEUE_MEMBER_LIST</ref>
620  <ref type="function">QUEUE_MEMBER_PENALTY</ref>
621  <ref type="function">QUEUE_MEMBER_STATUS</ref>
622  <ref type="function">QUEUE_MEMBER_PAUSED</ref>
623  </see-also>
624  </function>
625  <function name="QUEUE_WAITING_COUNT" language="en_US">
626  <synopsis>
627  Count number of calls currently waiting in a queue.
628  </synopsis>
629  <syntax>
630  <parameter name="queuename" />
631  </syntax>
632  <description>
633  <para>Returns the number of callers currently waiting in the specified <replaceable>queuename</replaceable>.</para>
634  </description>
635  <see-also>
636  <ref type="application">Queue</ref>
637  <ref type="application">QueueLog</ref>
638  <ref type="application">AddQueueMember</ref>
639  <ref type="application">RemoveQueueMember</ref>
640  <ref type="application">PauseQueueMember</ref>
641  <ref type="application">UnpauseQueueMember</ref>
642  <ref type="function">QUEUE_VARIABLES</ref>
643  <ref type="function">QUEUE_MEMBER</ref>
644  <ref type="function">QUEUE_MEMBER_COUNT</ref>
645  <ref type="function">QUEUE_EXISTS</ref>
646  <ref type="function">QUEUE_WAITING_COUNT</ref>
647  <ref type="function">QUEUE_MEMBER_LIST</ref>
648  <ref type="function">QUEUE_MEMBER_PENALTY</ref>
649  <ref type="function">QUEUE_MEMBER_STATUS</ref>
650  <ref type="function">QUEUE_MEMBER_PAUSED</ref>
651  </see-also>
652  </function>
653  <function name="QUEUE_MEMBER_LIST" language="en_US">
654  <synopsis>
655  Returns a list of interfaces on a queue.
656  </synopsis>
657  <syntax>
658  <parameter name="queuename" required="true" />
659  </syntax>
660  <description>
661  <para>Returns a comma-separated list of members associated with the specified <replaceable>queuename</replaceable>.</para>
662  </description>
663  <see-also>
664  <ref type="application">Queue</ref>
665  <ref type="application">QueueLog</ref>
666  <ref type="application">AddQueueMember</ref>
667  <ref type="application">RemoveQueueMember</ref>
668  <ref type="application">PauseQueueMember</ref>
669  <ref type="application">UnpauseQueueMember</ref>
670  <ref type="function">QUEUE_VARIABLES</ref>
671  <ref type="function">QUEUE_MEMBER</ref>
672  <ref type="function">QUEUE_MEMBER_COUNT</ref>
673  <ref type="function">QUEUE_EXISTS</ref>
674  <ref type="function">QUEUE_WAITING_COUNT</ref>
675  <ref type="function">QUEUE_MEMBER_LIST</ref>
676  <ref type="function">QUEUE_MEMBER_PENALTY</ref>
677  <ref type="function">QUEUE_MEMBER_STATUS</ref>
678  <ref type="function">QUEUE_MEMBER_PAUSED</ref>
679  </see-also>
680  </function>
681  <function name="QUEUE_MEMBER_PENALTY" language="en_US">
682  <synopsis>
683  Gets or sets queue members penalty.
684  </synopsis>
685  <syntax>
686  <parameter name="queuename" required="true" />
687  <parameter name="interface" required="true" />
688  </syntax>
689  <description>
690  <para>Gets or sets queue members penalty.</para>
691  </description>
692  <see-also>
693  <ref type="application">Queue</ref>
694  <ref type="application">QueueLog</ref>
695  <ref type="application">AddQueueMember</ref>
696  <ref type="application">RemoveQueueMember</ref>
697  <ref type="application">PauseQueueMember</ref>
698  <ref type="application">UnpauseQueueMember</ref>
699  <ref type="function">QUEUE_VARIABLES</ref>
700  <ref type="function">QUEUE_MEMBER</ref>
701  <ref type="function">QUEUE_MEMBER_COUNT</ref>
702  <ref type="function">QUEUE_EXISTS</ref>
703  <ref type="function">QUEUE_WAITING_COUNT</ref>
704  <ref type="function">QUEUE_MEMBER_LIST</ref>
705  <ref type="function">QUEUE_MEMBER_PENALTY</ref>
706  <ref type="function">QUEUE_MEMBER_STATUS</ref>
707  <ref type="function">QUEUE_MEMBER_PAUSED</ref>
708  </see-also>
709  </function>
710  <function name="QUEUE_MEMBER_STATUS" language="en_US">
711  <synopsis>
712  Returns a list of interfaces on a queue.
713  </synopsis>
714  <syntax>
715  <parameter name="queuename" required="false" />
716  <parameter name="member" required="true" />
717  </syntax>
718  <description>
719  <para>Returns status of <replaceable>member</replaceable> in queue <replaceable>queuename</replaceable> or a comma separated list for all queues.</para>
720  </description>
721  <see-also>
722  <ref type="application">Queue</ref>
723  <ref type="application">QueueLog</ref>
724  <ref type="application">AddQueueMember</ref>
725  <ref type="application">RemoveQueueMember</ref>
726  <ref type="application">PauseQueueMember</ref>
727  <ref type="application">UnpauseQueueMember</ref>
728  <ref type="function">QUEUE_VARIABLES</ref>
729  <ref type="function">QUEUE_MEMBER</ref>
730  <ref type="function">QUEUE_MEMBER_COUNT</ref>
731  <ref type="function">QUEUE_EXISTS</ref>
732  <ref type="function">QUEUE_WAITING_COUNT</ref>
733  <ref type="function">QUEUE_MEMBER_LIST</ref>
734  <ref type="function">QUEUE_MEMBER_PENALTY</ref>
735  <ref type="function">QUEUE_MEMBER_STATUS</ref>
736  <ref type="function">QUEUE_MEMBER_PAUSED</ref>
737  </see-also>
738  </function>
739  <function name="QUEUE_MEMBER_PAUSED" language="en_US">
740  <synopsis>
741  Returns a list of paused member interfaces on a queue
742  </synopsis>
743  <syntax>
744  <parameter name="queuename" required="false" />
745  <parameter name="member" required="true" />
746  </syntax>
747  <description>
748  <para>Returns pause state of <replaceable>member</replaceable> in queue <replaceable>queuename</replaceable> or a comma separated list of queue:status for all queues.</para>
749  </description>
750  <see-also>
751  <ref type="application">Queue</ref>
752  <ref type="application">QueueLog</ref>
753  <ref type="application">AddQueueMember</ref>
754  <ref type="application">RemoveQueueMember</ref>
755  <ref type="application">PauseQueueMember</ref>
756  <ref type="application">UnpauseQueueMember</ref>
757  <ref type="function">QUEUE_VARIABLES</ref>
758  <ref type="function">QUEUE_MEMBER</ref>
759  <ref type="function">QUEUE_MEMBER_COUNT</ref>
760  <ref type="function">QUEUE_EXISTS</ref>
761  <ref type="function">QUEUE_WAITING_COUNT</ref>
762  <ref type="function">QUEUE_MEMBER_LIST</ref>
763  <ref type="function">QUEUE_MEMBER_PENALTY</ref>
764  <ref type="function">QUEUE_MEMBER_STATUS</ref>
765  <ref type="function">QUEUE_MEMBER_PAUSED</ref>
766  </see-also>
767  </function>
768  <manager name="Queues" language="en_US">
769  <synopsis>
770  Queues.
771  </synopsis>
772  <syntax>
773  </syntax>
774  <description>
775  <para>Show queues information.</para>
776  </description>
777  </manager>
778  <manager name="QueueStatus" language="en_US">
779  <synopsis>
780  Show queue status.
781  </synopsis>
782  <syntax>
783  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
784  <parameter name="Queue">
785  <para>Limit the response to the status of the specified queue.</para>
786  </parameter>
787  <parameter name="Member">
788  <para>Limit the response to the status of the specified member.</para>
789  </parameter>
790  </syntax>
791  <description>
792  <para>Check the status of one or more queues.</para>
793  </description>
794  </manager>
795  <manager name="QueueSummary" language="en_US">
796  <synopsis>
797  Show queue summary.
798  </synopsis>
799  <syntax>
800  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
801  <parameter name="Queue">
802  <para>Queue for which the summary is requested.</para>
803  </parameter>
804  </syntax>
805  <description>
806  <para>Request the manager to send a QueueSummary event.</para>
807  </description>
808  </manager>
809  <manager name="QueueAdd" language="en_US">
810  <synopsis>
811  Add interface to queue.
812  </synopsis>
813  <syntax>
814  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
815  <parameter name="Queue" required="true">
816  <para>Queue's name.</para>
817  </parameter>
818  <parameter name="Interface" required="true">
819  <para>The name of the interface (tech/name) to add to the queue.</para>
820  </parameter>
821  <parameter name="Penalty">
822  <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>
823  </parameter>
824  <parameter name="Paused">
825  <para>To pause or not the member initially (true/false or 1/0).</para>
826  </parameter>
827  <parameter name="MemberName">
828  <para>Text alias for the interface.</para>
829  </parameter>
830  <parameter name="StateInterface" />
831  </syntax>
832  <description>
833  </description>
834  </manager>
835  <manager name="QueueRemove" language="en_US">
836  <synopsis>
837  Remove interface from queue.
838  </synopsis>
839  <syntax>
840  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
841  <parameter name="Queue" required="true">
842  <para>The name of the queue to take action on.</para>
843  </parameter>
844  <parameter name="Interface" required="true">
845  <para>The interface (tech/name) to remove from queue.</para>
846  </parameter>
847  </syntax>
848  <description>
849  </description>
850  </manager>
851  <manager name="QueuePause" language="en_US">
852  <synopsis>
853  Makes a queue member temporarily unavailable.
854  </synopsis>
855  <syntax>
856  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
857  <parameter name="Interface" required="true">
858  <para>The name of the interface (tech/name) to pause or unpause.</para>
859  </parameter>
860  <parameter name="Paused" required="true">
861  <para>Pause or unpause the interface. Set to 'true' to pause the member or 'false' to unpause.</para>
862  </parameter>
863  <parameter name="Queue">
864  <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>
865  </parameter>
866  <parameter name="Reason">
867  <para>Text description, returned in the event QueueMemberPaused.</para>
868  </parameter>
869  </syntax>
870  <description>
871  <para>Pause or unpause a member in a queue.</para>
872  </description>
873  </manager>
874  <manager name="QueueLog" language="en_US">
875  <synopsis>
876  Adds custom entry in queue_log.
877  </synopsis>
878  <syntax>
879  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
880  <parameter name="Queue" required="true" />
881  <parameter name="Event" required="true" />
882  <parameter name="Uniqueid" />
883  <parameter name="Interface" />
884  <parameter name="Message" />
885  </syntax>
886  <description>
887  </description>
888  </manager>
889  <manager name="QueuePenalty" language="en_US">
890  <synopsis>
891  Set the penalty for a queue member.
892  </synopsis>
893  <syntax>
894  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
895  <parameter name="Interface" required="true">
896  <para>The interface (tech/name) of the member whose penalty to change.</para>
897  </parameter>
898  <parameter name="Penalty" required="true">
899  <para>The new penalty (number) for the member. Must be nonnegative.</para>
900  </parameter>
901  <parameter name="Queue">
902  <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>
903  </parameter>
904  </syntax>
905  <description>
906  <para>Change the penalty of a queue member</para>
907  </description>
908  </manager>
909  <manager name="QueueRule" language="en_US">
910  <synopsis>
911  Queue Rules.
912  </synopsis>
913  <syntax>
914  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
915  <parameter name="Rule">
916  <para>The name of the rule in queuerules.conf whose contents to list.</para>
917  </parameter>
918  </syntax>
919  <description>
920  <para>List queue rules defined in queuerules.conf</para>
921  </description>
922  </manager>
923  <manager name="QueueReload" language="en_US">
924  <synopsis>
925  Reload a queue, queues, or any sub-section of a queue or queues.
926  </synopsis>
927  <syntax>
928  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
929  <parameter name="Queue">
930  <para>The name of the queue to take action on. If no queue name is specified, then all queues are affected.</para>
931  </parameter>
932  <parameter name="Members">
933  <para>Whether to reload the queue's members.</para>
934  <enumlist>
935  <enum name="yes" />
936  <enum name="no" />
937  </enumlist>
938  </parameter>
939  <parameter name="Rules">
940  <para>Whether to reload queuerules.conf</para>
941  <enumlist>
942  <enum name="yes" />
943  <enum name="no" />
944  </enumlist>
945  </parameter>
946  <parameter name="Parameters">
947  <para>Whether to reload the other queue options.</para>
948  <enumlist>
949  <enum name="yes" />
950  <enum name="no" />
951  </enumlist>
952  </parameter>
953  </syntax>
954  <description>
955  </description>
956  </manager>
957  <manager name="QueueReset" language="en_US">
958  <synopsis>
959  Reset queue statistics.
960  </synopsis>
961  <syntax>
962  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
963  <parameter name="Queue">
964  <para>The name of the queue on which to reset statistics.</para>
965  </parameter>
966  </syntax>
967  <description>
968  <para>Reset the statistics for a queue.</para>
969  </description>
970  </manager>
971  ***/
972 
973 enum {
982 };
983 
984 enum {
988 };
989 
993  QUEUE_RELOAD_RULES = (1 << 2),
994  QUEUE_RESET_STATS = (1 << 3),
995 };
996 
997 static const struct strategy {
998  int strategy;
999  const char *name;
1000 } strategies[] = {
1001  { QUEUE_STRATEGY_RINGALL, "ringall" },
1002  { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
1003  { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
1004  { QUEUE_STRATEGY_RANDOM, "random" },
1005  { QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
1006  { QUEUE_STRATEGY_RRMEMORY, "roundrobin" },
1007  { QUEUE_STRATEGY_LINEAR, "linear" },
1008  { QUEUE_STRATEGY_WRANDOM, "wrandom"},
1009  { QUEUE_STRATEGY_RRORDERED, "rrordered"},
1010 };
1011 
1012 static const struct autopause {
1014  const char *name;
1015 } autopausesmodes [] = {
1016  { QUEUE_AUTOPAUSE_OFF,"no" },
1017  { QUEUE_AUTOPAUSE_ON, "yes" },
1018  { QUEUE_AUTOPAUSE_ALL,"all" },
1019 };
1020 
1021 
1023 
1024 #define DEFAULT_RETRY 5
1025 #define DEFAULT_TIMEOUT 15
1026 #define RECHECK 1 /*!< Recheck every second to see we we're at the top yet */
1027 #define MAX_PERIODIC_ANNOUNCEMENTS 10 /*!< The maximum periodic announcements we can have */
1028 #define DEFAULT_MIN_ANNOUNCE_FREQUENCY 15 /*!< The minimum number of seconds between position announcements \
1029  The default value of 15 provides backwards compatibility */
1030 #define MAX_QUEUE_BUCKETS 53
1032 #define RES_OKAY 0 /*!< Action completed */
1033 #define RES_EXISTS (-1) /*!< Entry already exists */
1034 #define RES_OUTOFMEMORY (-2) /*!< Out of memory */
1035 #define RES_NOSUCHQUEUE (-3) /*!< No such queue */
1036 #define RES_NOT_DYNAMIC (-4) /*!< Member is not dynamic */
1038 static char *app = "Queue";
1040 static char *app_aqm = "AddQueueMember" ;
1042 static char *app_rqm = "RemoveQueueMember" ;
1044 static char *app_pqm = "PauseQueueMember" ;
1046 static char *app_upqm = "UnpauseQueueMember" ;
1048 static char *app_ql = "QueueLog" ;
1050 /*! \brief Persistent Members astdb family */
1051 static const char * const pm_family = "Queue/PersistentMembers";
1053 /*! \brief queues.conf [general] extra debug option */
1054 static int queue_debug = 0;
1056 /*! \brief queues.conf [general] option */
1057 static int queue_persistent_members = 0;
1059 /*! \brief queues.conf per-queue weight option */
1060 static int use_weight = 0;
1062 /*! \brief queues.conf [general] option */
1063 static int autofill_default = 1;
1065 /*! \brief queues.conf [general] option */
1066 static int montype_default = 0;
1068 /*! \brief queues.conf [general] option */
1069 static int shared_lastcall = 1;
1071 /*! \brief Subscription to device state change events */
1072 static struct ast_event_sub *device_state_sub;
1074 /*! \brief queues.conf [general] option */
1075 static int update_cdr = 0;
1077 enum queue_result {
1086 };
1087 
1088 static const struct {
1089  enum queue_result id;
1090  char *text;
1092  { QUEUE_UNKNOWN, "UNKNOWN" },
1093  { QUEUE_TIMEOUT, "TIMEOUT" },
1094  { QUEUE_JOINEMPTY,"JOINEMPTY" },
1095  { QUEUE_LEAVEEMPTY, "LEAVEEMPTY" },
1096  { QUEUE_JOINUNAVAIL, "JOINUNAVAIL" },
1097  { QUEUE_LEAVEUNAVAIL, "LEAVEUNAVAIL" },
1098  { QUEUE_FULL, "FULL" },
1099  { QUEUE_CONTINUE, "CONTINUE" },
1100 };
1101 
1105 };
1106 
1107 /*! \brief We define a custom "local user" structure because we
1108  * use it not only for keeping track of what is in use but
1109  * also for keeping track of who we're dialing.
1110  *
1111  * There are two "links" defined in this structure, q_next and call_next.
1112  * q_next links ALL defined callattempt structures into a linked list. call_next is
1113  * a link which allows for a subset of the callattempts to be traversed. This subset
1114  * is used in wait_for_answer so that irrelevant callattempts are not traversed. This
1115  * also is helpful so that queue logs are always accurate in the case where a call to
1116  * a member times out, especially if using the ringall strategy.
1117 */
1118 
1119 struct callattempt {
1123  char interface[256];
1124  int metric;
1125  time_t lastcall;
1127  struct member *member;
1128  /*! Saved connected party info from an AST_CONTROL_CONNECTED_LINE. */
1130  /*! TRUE if an AST_CONTROL_CONNECTED_LINE update was saved to the connected element. */
1131  unsigned int pending_connected_update:1;
1132  /*! TRUE if the connected line update is blocked. */
1133  unsigned int block_connected_update:1;
1134  /*! TRUE if caller id is not available for connected line */
1135  unsigned int dial_callerid_absent:1;
1136  /*! TRUE if the call is still active */
1137  unsigned int stillgoing:1;
1139 };
1140 
1141 
1142 struct queue_ent {
1143  struct call_queue *parent; /*!< What queue is our parent */
1144  char moh[80]; /*!< Name of musiconhold to be used */
1145  char announce[PATH_MAX]; /*!< Announcement to play for member when call is answered */
1146  char context[AST_MAX_CONTEXT]; /*!< Context when user exits queue */
1147  char digits[AST_MAX_EXTENSION]; /*!< Digits entered while in queue */
1148  int valid_digits; /*!< Digits entered correspond to valid extension. Exited */
1149  int pos; /*!< Where we are in the queue */
1150  int prio; /*!< Our priority */
1151  int last_pos_said; /*!< Last position we told the user */
1152  int ring_when_ringing; /*!< Should we only use ring indication when a channel is ringing? */
1153  time_t last_periodic_announce_time; /*!< The last time we played a periodic announcement */
1154  int last_periodic_announce_sound; /*!< The last periodic announcement we made */
1155  time_t last_pos; /*!< Last time we told the user their position */
1156  int opos; /*!< Where we started in the queue */
1157  int handled; /*!< Whether our call was handled */
1158  int tries; /*!< How many times we have tried to call this entry */
1159  int pending; /*!< Non-zero if we are attempting to call a member */
1160  int max_penalty; /*!< Limit the members that can take this call to this penalty or lower */
1161  int min_penalty; /*!< Limit the members that can take this call to this penalty or higher */
1162  int linpos; /*!< If using linear strategy, what position are we at? */
1163  int linwrapped; /*!< Is the linpos wrapped? */
1164  time_t start; /*!< When we started holding */
1165  time_t expire; /*!< When this entry should expire (time out of queue) */
1166  int cancel_answered_elsewhere; /*!< Whether we should force the CAE flag on this call (C) option*/
1167  struct ast_channel *chan; /*!< Our channel */
1168  AST_LIST_HEAD_NOLOCK(,penalty_rule) qe_rules; /*!< Local copy of the queue's penalty rules */
1169  struct penalty_rule *pr; /*!< Pointer to the next penalty rule to implement */
1170  struct queue_ent *next; /*!< The next queue entry */
1171 };
1172 
1173 struct member {
1174  char interface[80]; /*!< Technology/Location to dial to reach this member*/
1175  char state_exten[AST_MAX_EXTENSION]; /*!< Extension to get state from (if using hint) */
1176  char state_context[AST_MAX_CONTEXT]; /*!< Context to use when getting state (if using hint) */
1177  char state_interface[80]; /*!< Technology/Location from which to read devicestate changes */
1178  char membername[80]; /*!< Member name to use in queue logs */
1179  int penalty; /*!< Are we a last resort? */
1180  int calls; /*!< Number of calls serviced by this member */
1181  int dynamic; /*!< Are we dynamically added? */
1182  int realtime; /*!< Is this member realtime? */
1183  int status; /*!< Status of queue member */
1184  int paused; /*!< Are we paused (not accepting calls)? */
1185  int queuepos; /*!< In what order (pertains to certain strategies) should this member be called? */
1186  time_t lastcall; /*!< When last successful call was hungup */
1187  struct call_queue *lastqueue; /*!< Last queue we received a call */
1188  unsigned int dead:1; /*!< Used to detect members deleted in realtime */
1189  int ringcount; /*!< Number of rings to allow per queue call */
1190  unsigned int delme:1; /*!< Flag to delete entry on reload */
1191  unsigned int call_pending:1; /*!< TRUE if the Q is attempting to place a call to the member. */
1192  char rt_uniqueid[80]; /*!< Unique id of realtime member entry */
1193 };
1194 
1195 enum empty_conditions {
1198  QUEUE_EMPTY_INUSE = (1 << 2),
1204 };
1205 
1206 /* values used in multi-bit flags in call_queue */
1207 #define ANNOUNCEHOLDTIME_ALWAYS 1
1208 #define ANNOUNCEHOLDTIME_ONCE 2
1209 #define QUEUE_EVENT_VARIABLES 3
1211 struct penalty_rule {
1212  int time; /*!< Number of seconds that need to pass before applying this rule */
1213  int max_value; /*!< The amount specified in the penalty rule for max penalty */
1214  int min_value; /*!< The amount specified in the penalty rule for min penalty */
1215  int max_relative; /*!< Is the max adjustment relative? 1 for relative, 0 for absolute */
1216  int min_relative; /*!< Is the min adjustment relative? 1 for relative, 0 for absolute */
1217  AST_LIST_ENTRY(penalty_rule) list; /*!< Next penalty_rule */
1218 };
1219 
1220 #define ANNOUNCEPOSITION_YES 1 /*!< We announce position */
1221 #define ANNOUNCEPOSITION_NO 2 /*!< We don't announce position */
1222 #define ANNOUNCEPOSITION_MORE_THAN 3 /*!< We say "Currently there are more than <limit>" */
1223 #define ANNOUNCEPOSITION_LIMIT 4 /*!< We not announce position more than <limit> */
1225 struct call_queue {
1227  /*! Queue name */
1229  /*! Music on Hold class */
1231  /*! Announcement to play when call is answered */
1233  /*! Exit context */
1235  /*! Macro to run upon member connection */
1236  AST_STRING_FIELD(membermacro);
1237  /*! Gosub to run upon member connection */
1238  AST_STRING_FIELD(membergosub);
1239  /*! Default rule to use if none specified in call to Queue() */
1240  AST_STRING_FIELD(defaultrule);
1241  /*! Sound file: "Your call is now first in line" (def. queue-youarenext) */
1242  AST_STRING_FIELD(sound_next);
1243  /*! Sound file: "There are currently" (def. queue-thereare) */
1244  AST_STRING_FIELD(sound_thereare);
1245  /*! Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting) */
1246  AST_STRING_FIELD(sound_calls);
1247  /*! Sound file: "Currently there are more than" (def. queue-quantity1) */
1248  AST_STRING_FIELD(queue_quantity1);
1249  /*! Sound file: "callers waiting to speak with a representative" (def. queue-quantity2) */
1250  AST_STRING_FIELD(queue_quantity2);
1251  /*! Sound file: "The current estimated total holdtime is" (def. queue-holdtime) */
1252  AST_STRING_FIELD(sound_holdtime);
1253  /*! Sound file: "minutes." (def. queue-minutes) */
1254  AST_STRING_FIELD(sound_minutes);
1255  /*! Sound file: "minute." (def. queue-minute) */
1256  AST_STRING_FIELD(sound_minute);
1257  /*! Sound file: "seconds." (def. queue-seconds) */
1258  AST_STRING_FIELD(sound_seconds);
1259  /*! Sound file: "Thank you for your patience." (def. queue-thankyou) */
1260  AST_STRING_FIELD(sound_thanks);
1261  /*! Sound file: Custom announce for caller, no default */
1262  AST_STRING_FIELD(sound_callerannounce);
1263  /*! Sound file: "Hold time" (def. queue-reporthold) */
1264  AST_STRING_FIELD(sound_reporthold);
1265  );
1266  /*! Sound files: Custom announce, no default */
1267  struct ast_str *sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS];
1268  unsigned int dead:1;
1269  unsigned int eventwhencalled:2;
1270  unsigned int ringinuse:1;
1271  unsigned int announce_to_first_user:1; /*!< Whether or not we announce to the first user in a queue */
1272  unsigned int setinterfacevar:1;
1273  unsigned int setqueuevar:1;
1274  unsigned int setqueueentryvar:1;
1275  unsigned int reportholdtime:1;
1276  unsigned int wrapped:1;
1277  unsigned int timeoutrestart:1;
1278  unsigned int announceholdtime:2;
1279  unsigned int announceposition:3;
1280  int strategy:4;
1281  unsigned int maskmemberstatus:1;
1282  unsigned int realtime:1;
1283  unsigned int found:1;
1284  unsigned int relativeperiodicannounce:1;
1285  enum empty_conditions joinempty;
1286  enum empty_conditions leavewhenempty;
1287  int announcepositionlimit; /*!< How many positions we announce? */
1288  int announcefrequency; /*!< How often to announce their position */
1289  int minannouncefrequency; /*!< The minimum number of seconds between position announcements (def. 15) */
1290  int periodicannouncefrequency; /*!< How often to play periodic announcement */
1291  int numperiodicannounce; /*!< The number of periodic announcements configured */
1292  int randomperiodicannounce; /*!< Are periodic announcments randomly chosen */
1293  int roundingseconds; /*!< How many seconds do we round to? */
1294  int holdtime; /*!< Current avg holdtime, based on an exponential average */
1295  int talktime; /*!< Current avg talktime, based on the same exponential average */
1296  int callscompleted; /*!< Number of queue calls completed */
1297  int callsabandoned; /*!< Number of queue calls abandoned */
1298  int servicelevel; /*!< seconds setting for servicelevel*/
1299  int callscompletedinsl; /*!< Number of calls answered with servicelevel*/
1300  char monfmt[8]; /*!< Format to use when recording calls */
1301  int montype; /*!< Monitor type Monitor vs. MixMonitor */
1302  int count; /*!< How many entries */
1303  int maxlen; /*!< Max number of entries */
1304  int wrapuptime; /*!< Wrapup Time */
1305  int penaltymemberslimit; /*!< Disregard penalty when queue has fewer than this many members */
1306  int ringlimit; /*!< Max number of rings per entry in queue */
1308  int retry; /*!< Retry calling everyone after this amount of time */
1309  int timeout; /*!< How long to wait for an answer */
1310  int weight; /*!< Respective weight */
1311  int autopause; /*!< Auto pause queue members if they fail to answer */
1312  int timeoutpriority; /*!< Do we allow a fraction of the timeout to occur for a ring? */
1314  /* Queue strategy things */
1315  int rrpos; /*!< Round Robin - position */
1316  int memberdelay; /*!< Seconds to delay connecting member to caller */
1317  int autofill; /*!< Ignore the head call status and ring an available agent */
1319  struct ao2_container *members; /*!< Head of the list of members */
1320  struct queue_ent *head; /*!< Head of the list of callers */
1321  AST_LIST_ENTRY(call_queue) list; /*!< Next call queue */
1322  AST_LIST_HEAD_NOLOCK(, penalty_rule) rules; /*!< The list of penalty rules to invoke */
1323 };
1324 
1325 struct rule_list {
1326  char name[80];
1328  AST_LIST_ENTRY(rule_list) list;
1329 };
1330 
1331 static AST_LIST_HEAD_STATIC(rule_lists, rule_list);
1333 static struct ao2_container *queues;
1335 static void update_realtime_members(struct call_queue *q);
1336 static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
1337 
1338 static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
1339 /*! \brief sets the QUEUESTATUS channel variable */
1340 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
1342  int i;
1343 
1344  for (i = 0; i < ARRAY_LEN(queue_results); i++) {
1345  if (queue_results[i].id == res) {
1346  pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
1347  return;
1348  }
1349  }
1350 }
1351 
1352 static const char *int2strat(int strategy)
1354  int x;
1355 
1356  for (x = 0; x < ARRAY_LEN(strategies); x++) {
1357  if (strategy == strategies[x].strategy)
1358  return strategies[x].name;
1359  }
1360 
1361  return "<unknown>";
1362 }
1363 
1364 static int strat2int(const char *strategy)
1366  int x;
1367 
1368  for (x = 0; x < ARRAY_LEN(strategies); x++) {
1369  if (!strcasecmp(strategy, strategies[x].name))
1370  return strategies[x].strategy;
1371  }
1372 
1373  return -1;
1374 }
1375 
1376 static int autopause2int(const char *autopause)
1378  int x;
1379  /*This 'double check' that default value is OFF */
1380  if (ast_strlen_zero(autopause))
1381  return QUEUE_AUTOPAUSE_OFF;
1382 
1383  /*This 'double check' is to ensure old values works */
1384  if(ast_true(autopause))
1385  return QUEUE_AUTOPAUSE_ON;
1386 
1387  for (x = 0; x < ARRAY_LEN(autopausesmodes); x++) {
1388  if (!strcasecmp(autopause, autopausesmodes[x].name))
1389  return autopausesmodes[x].autopause;
1390  }
1391 
1392  /*This 'double check' that default value is OFF */
1393  return QUEUE_AUTOPAUSE_OFF;
1394 }
1395 
1396 static int queue_hash_cb(const void *obj, const int flags)
1398  const struct call_queue *q = obj;
1399 
1400  return ast_str_case_hash(q->name);
1401 }
1402 
1403 static int queue_cmp_cb(void *obj, void *arg, int flags)
1405  struct call_queue *q = obj, *q2 = arg;
1406  return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0;
1407 }
1408 
1409 /*! \internal
1410  * \brief ao2_callback, Decreases queuepos of all followers with a queuepos greater than arg.
1411  * \param obj the member being acted on
1412  * \param arg pointer to an integer containing the position value that was removed and requires reduction for anything above
1413  */
1414 static int queue_member_decrement_followers(void *obj, void *arg, int flag)
1416  struct member *mem = obj;
1417  int *decrement_followers_after = arg;
1418 
1419  if (mem->queuepos > *decrement_followers_after) {
1420  mem->queuepos--;
1421  }
1422 
1423  return 0;
1424 }
1425 
1426 /*! \internal
1427  * \brief ao2_callback, finds members in a queue marked for deletion and in a cascading fashion runs queue_member_decrement_followers
1428  * on them. This callback should always be ran before performing mass unlinking of delmarked members from queues.
1429  * \param obj member being acted on
1430  * \param arg pointer to the queue members are being removed from
1431  */
1432 static int queue_delme_members_decrement_followers(void *obj, void *arg, int flag)
1434  struct member *mem = obj;
1435  struct call_queue *queue = arg;
1436  int rrpos = mem->queuepos;
1437 
1438  if (mem->delme) {
1440  }
1441 
1442  return 0;
1443 }
1444 
1445 /*! \internal
1446  * \brief Use this to decrement followers during removal of a member
1447  * \param queue which queue the member is being removed from
1448  * \param mem which member is being removed from the queue
1449  */
1450 static void queue_member_follower_removal(struct call_queue *queue, struct member *mem)
1452  int pos = mem->queuepos;
1453 
1454  /* 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
1455  * who would have been next otherwise. */
1456  if (pos < queue->rrpos) {
1457  queue->rrpos--;
1458  }
1459 
1461 }
1462 
1463 #ifdef REF_DEBUG_ONLY_QUEUES
1464 #define queue_ref(a) __ao2_ref_debug(a,1,"",__FILE__,__LINE__,__PRETTY_FUNCTION__)
1465 #define queue_unref(a) __ao2_ref_debug(a,-1,"",__FILE__,__LINE__,__PRETTY_FUNCTION__)
1466 #define queue_t_ref(a,b) __ao2_ref_debug(a,1,b,__FILE__,__LINE__,__PRETTY_FUNCTION__)
1467 #define queue_t_unref(a,b) __ao2_ref_debug(a,-1,b,__FILE__,__LINE__,__PRETTY_FUNCTION__)
1468 #define queues_t_link(c,q,tag) __ao2_link_debug(c,q,tag,__FILE__,__LINE__,__PRETTY_FUNCTION__)
1469 #define queues_t_unlink(c,q,tag) __ao2_unlink_debug(c,q,tag,__FILE__,__LINE__,__PRETTY_FUNCTION__)
1470 #else
1471 #define queue_t_ref(a,b) queue_ref(a)
1472 #define queue_t_unref(a,b) queue_unref(a)
1473 #define queues_t_link(c,q,tag) ao2_t_link(c,q,tag)
1474 #define queues_t_unlink(c,q,tag) ao2_t_unlink(c,q,tag)
1475 static inline struct call_queue *queue_ref(struct call_queue *q)
1477  ao2_ref(q, 1);
1478  return q;
1479 }
1480 
1481 static inline struct call_queue *queue_unref(struct call_queue *q)
1483  ao2_ref(q, -1);
1484  return NULL;
1485 }
1486 #endif
1487 
1488 /*! \brief Set variables of queue */
1489 static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
1491  char interfacevar[256]="";
1492  float sl = 0;
1493 
1494  ao2_lock(q);
1495 
1496  if (q->setqueuevar) {
1497  sl = 0;
1498  if (q->callscompleted > 0)
1499  sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
1500 
1501  snprintf(interfacevar, sizeof(interfacevar),
1502  "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
1503  q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned, q->servicelevel, sl);
1504 
1505  ao2_unlock(q);
1506 
1507  pbx_builtin_setvar_multiple(chan, interfacevar);
1508  } else {
1509  ao2_unlock(q);
1510  }
1511 }
1512 
1513 /*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
1514 static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
1516  struct queue_ent *cur;
1517 
1518  if (!q || !new)
1519  return;
1520  if (prev) {
1521  cur = prev->next;
1522  prev->next = new;
1523  } else {
1524  cur = q->head;
1525  q->head = new;
1526  }
1527  new->next = cur;
1528 
1529  /* every queue_ent must have a reference to it's parent call_queue, this
1530  * reference does not go away until the end of the queue_ent's life, meaning
1531  * that even when the queue_ent leaves the call_queue this ref must remain. */
1532  queue_ref(q);
1533  new->parent = q;
1534  new->pos = ++(*pos);
1535  new->opos = *pos;
1536 }
1537 
1538 /*! \brief Check if members are available
1539  *
1540  * This function checks to see if members are available to be called. If any member
1541  * is available, the function immediately returns 0. If no members are available,
1542  * then -1 is returned.
1543  */
1544 static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, enum empty_conditions conditions, int devstate)
1546  struct member *member;
1547  struct ao2_iterator mem_iter;
1548 
1549  ao2_lock(q);
1550  mem_iter = ao2_iterator_init(q->members, 0);
1551  for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
1552  if ((max_penalty != INT_MAX && member->penalty > max_penalty) || (min_penalty != INT_MAX && member->penalty < min_penalty)) {
1553  if (conditions & QUEUE_EMPTY_PENALTY) {
1554  ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
1555  continue;
1556  }
1557  }
1558 
1559  switch (devstate ? ast_device_state(member->state_interface) : member->status) {
1560  case AST_DEVICE_INVALID:
1561  if (conditions & QUEUE_EMPTY_INVALID) {
1562  ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername);
1563  break;
1564  }
1565  goto default_case;
1567  if (conditions & QUEUE_EMPTY_UNAVAILABLE) {
1568  ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername);
1569  break;
1570  }
1571  goto default_case;
1572  case AST_DEVICE_INUSE:
1573  if (conditions & QUEUE_EMPTY_INUSE) {
1574  ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername);
1575  break;
1576  }
1577  goto default_case;
1578  case AST_DEVICE_RINGING:
1579  if (conditions & QUEUE_EMPTY_RINGING) {
1580  ast_debug(4, "%s is unavailable because his device state is 'ringing'\n", member->membername);
1581  break;
1582  }
1583  goto default_case;
1584  case AST_DEVICE_UNKNOWN:
1585  if (conditions & QUEUE_EMPTY_UNKNOWN) {
1586  ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername);
1587  break;
1588  }
1589  /* Fall-through */
1590  default:
1591  default_case:
1592  if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) {
1593  ast_debug(4, "%s is unavailable because he is paused'\n", member->membername);
1594  break;
1595  } else if ((conditions & QUEUE_EMPTY_WRAPUP) && member->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < member->lastcall)) {
1596  ast_debug(4, "%s is unavailable because it has only been %d seconds since his last call (wrapup time is %d)\n", member->membername, (int) (time(NULL) - member->lastcall), q->wrapuptime);
1597  break;
1598  } else {
1599  ao2_ref(member, -1);
1600  ao2_iterator_destroy(&mem_iter);
1601  ao2_unlock(q);
1602  ast_debug(4, "%s is available.\n", member->membername);
1603  return 0;
1604  }
1605  break;
1606  }
1607  }
1608  ao2_iterator_destroy(&mem_iter);
1609  ao2_unlock(q);
1610 
1611  if (!devstate && (conditions & QUEUE_EMPTY_RINGING)) {
1612  /* member state still may be RINGING due to lag in event message - check again with device state */
1613  return get_member_status(q, max_penalty, min_penalty, conditions, 1);
1614  }
1615  return -1;
1616 }
1617 
1618 struct statechange {
1620  int state;
1621  char dev[0];
1622 };
1623 
1624 /*! \brief set a member's status based on device state of that member's state_interface.
1625  *
1626  * Lock interface list find sc, iterate through each queues queue_member list for member to
1627  * update state inside queues
1628 */
1629 static int update_status(struct call_queue *q, struct member *m, const int status)
1631  m->status = status;
1632 
1633  if (q->maskmemberstatus)
1634  return 0;
1635 
1636  manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
1637  "Queue: %s\r\n"
1638  "Location: %s\r\n"
1639  "MemberName: %s\r\n"
1640  "Membership: %s\r\n"
1641  "Penalty: %d\r\n"
1642  "CallsTaken: %d\r\n"
1643  "LastCall: %d\r\n"
1644  "Status: %d\r\n"
1645  "Paused: %d\r\n",
1646  q->name, m->interface, m->membername, m->dynamic ? "dynamic" : m->realtime ? "realtime" : "static",
1647  m->penalty, m->calls, (int)m->lastcall, m->status, m->paused
1648  );
1649 
1650  return 0;
1651 }
1652 
1653 /*! \brief set a member's status based on device state of that member's interface*/
1654 static int handle_statechange(void *datap)
1656  struct statechange *sc = datap;
1657  struct ao2_iterator miter, qiter;
1658  struct member *m;
1659  struct call_queue *q;
1660  char interface[80], *slash_pos;
1661  int found = 0;
1662 
1663  qiter = ao2_iterator_init(queues, 0);
1664  while ((q = ao2_t_iterator_next(&qiter, "Iterate over queues"))) {
1665  ao2_lock(q);
1666 
1667  miter = ao2_iterator_init(q->members, 0);
1668  for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
1669  ast_copy_string(interface, m->state_interface, sizeof(interface));
1670 
1671  if ((slash_pos = strchr(interface, '/')))
1672  if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/')))
1673  *slash_pos = '\0';
1674 
1675  if (!strcasecmp(interface, sc->dev)) {
1676  found = 1;
1677  update_status(q, m, sc->state);
1678  ao2_ref(m, -1);
1679  break;
1680  }
1681  }
1682  ao2_iterator_destroy(&miter);
1683 
1684  ao2_unlock(q);
1685  queue_t_unref(q, "Done with iterator");
1686  }
1687  ao2_iterator_destroy(&qiter);
1688 
1689  if (found)
1690  ast_debug(1, "Device '%s' changed to state '%d' (%s)\n", sc->dev, sc->state, ast_devstate2str(sc->state));
1691  else
1692  ast_debug(3, "Device '%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n", sc->dev, sc->state, ast_devstate2str(sc->state));
1693 
1694  ast_free(sc);
1695  return 0;
1696 }
1697 
1698 static void device_state_cb(const struct ast_event *event, void *unused)
1700  enum ast_device_state state;
1701  const char *device;
1702  struct statechange *sc;
1703  size_t datapsize;
1704 
1705  state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
1706  device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
1707 
1708  if (ast_strlen_zero(device)) {
1709  ast_log(LOG_ERROR, "Received invalid event that had no device IE\n");
1710  return;
1711  }
1712  datapsize = sizeof(*sc) + strlen(device) + 1;
1713  if (!(sc = ast_calloc(1, datapsize))) {
1714  ast_log(LOG_ERROR, "failed to calloc a state change struct\n");
1715  return;
1716  }
1717  sc->state = state;
1718  strcpy(sc->dev, device);
1719  if (ast_taskprocessor_push(devicestate_tps, handle_statechange, sc) < 0) {
1720  ast_free(sc);
1721  }
1722 }
1723 
1724 /*! \brief Helper function which converts from extension state to device state values */
1725 static int extensionstate2devicestate(int state)
1727  switch (state) {
1729  state = AST_DEVICE_NOT_INUSE;
1730  break;
1731  case AST_EXTENSION_INUSE:
1732  state = AST_DEVICE_INUSE;
1733  break;
1734  case AST_EXTENSION_BUSY:
1735  state = AST_DEVICE_BUSY;
1736  break;
1737  case AST_EXTENSION_RINGING:
1738  state = AST_DEVICE_RINGING;
1739  break;
1740  case AST_EXTENSION_ONHOLD:
1741  state = AST_DEVICE_ONHOLD;
1742  break;
1744  state = AST_DEVICE_UNAVAILABLE;
1745  break;
1746  case AST_EXTENSION_REMOVED:
1748  default:
1749  state = AST_DEVICE_INVALID;
1750  break;
1751  }
1752 
1753  return state;
1754 }
1755 
1756 static int extension_state_cb(char *context, char *exten, enum ast_extension_states state, void *data)
1758  struct ao2_iterator miter, qiter;
1759  struct member *m;
1760  struct call_queue *q;
1761  int found = 0, device_state = extensionstate2devicestate(state);
1762 
1763  qiter = ao2_iterator_init(queues, 0);
1764  while ((q = ao2_t_iterator_next(&qiter, "Iterate through queues"))) {
1765  ao2_lock(q);
1766 
1767  miter = ao2_iterator_init(q->members, 0);
1768  for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
1769  if (!strcmp(m->state_context, context) && !strcmp(m->state_exten, exten)) {
1770  update_status(q, m, device_state);
1771  ao2_ref(m, -1);
1772  found = 1;
1773  break;
1774  }
1775  }
1776  ao2_iterator_destroy(&miter);
1777 
1778  ao2_unlock(q);
1779  queue_t_unref(q, "Done with iterator");
1780  }
1781  ao2_iterator_destroy(&qiter);
1782 
1783  if (found) {
1784  ast_debug(1, "Extension '%s@%s' changed to state '%d' (%s)\n", exten, context, device_state, ast_devstate2str(device_state));
1785  } else {
1786  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",
1787  exten, context, device_state, ast_devstate2str(device_state));
1788  }
1789 
1790  return 0;
1791 }
1792 
1793 /*! \brief Return the current state of a member */
1794 static int get_queue_member_status(struct member *cur)
1797 }
1798 
1799 /*! \brief allocate space for new queue member and set fields based on parameters passed */
1800 static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface)
1802  struct member *cur;
1803 
1804  if ((cur = ao2_alloc(sizeof(*cur), NULL))) {
1805  cur->penalty = penalty;
1806  cur->paused = paused;
1807  ast_copy_string(cur->interface, interface, sizeof(cur->interface));
1808  if (!ast_strlen_zero(state_interface))
1809  ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface));
1810  else
1811  ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface));
1812  if (!ast_strlen_zero(membername))
1813  ast_copy_string(cur->membername, membername, sizeof(cur->membername));
1814  else
1815  ast_copy_string(cur->membername, interface, sizeof(cur->membername));
1816  if (!strchr(cur->interface, '/'))
1817  ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
1818  if (!strncmp(cur->state_interface, "hint:", 5)) {
1819  char *tmp = ast_strdupa(cur->state_interface), *context = tmp;
1820  char *exten = strsep(&context, "@") + 5;
1821 
1822  ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten));
1823  ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context));
1824  }
1825  cur->status = get_queue_member_status(cur);
1826  }
1827 
1828  return cur;
1829 }
1830 
1831 
1832 static int compress_char(const char c)
1834  if (c < 32)
1835  return 0;
1836  else if (c > 96)
1837  return c - 64;
1838  else
1839  return c - 32;
1840 }
1841 
1842 static int member_hash_fn(const void *obj, const int flags)
1844  const struct member *mem = obj;
1845  const char *chname = strchr(mem->interface, '/');
1846  int ret = 0, i;
1847  if (!chname)
1848  chname = mem->interface;
1849  for (i = 0; i < 5 && chname[i]; i++)
1850  ret += compress_char(chname[i]) << (i * 6);
1851  return ret;
1852 }
1853 
1854 static int member_cmp_fn(void *obj1, void *obj2, int flags)
1856  struct member *mem1 = obj1, *mem2 = obj2;
1857  return strcasecmp(mem1->interface, mem2->interface) ? 0 : CMP_MATCH | CMP_STOP;
1858 }
1859 
1860 /*!
1861  * \brief Initialize Queue default values.
1862  * \note the queue's lock must be held before executing this function
1863 */
1864 static void init_queue(struct call_queue *q)
1866  int i;
1867  struct penalty_rule *pr_iter;
1868 
1869  q->dead = 0;
1870  q->retry = DEFAULT_RETRY;
1871  q->timeout = DEFAULT_TIMEOUT;
1872  q->maxlen = 0;
1873  q->ringlimit = 0;
1874  q->announcefrequency = 0;
1876  q->announceholdtime = 1;
1877  q->announcepositionlimit = 10; /* Default 10 positions */
1878  q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */
1879  q->roundingseconds = 0; /* Default - don't announce seconds */
1880  q->servicelevel = 0;
1881  q->ringinuse = 1;
1882  q->announce_to_first_user = 0;
1883  q->setinterfacevar = 0;
1884  q->setqueuevar = 0;
1885  q->setqueueentryvar = 0;
1887  q->montype = montype_default;
1888  q->monfmt[0] = '\0';
1889  q->reportholdtime = 0;
1890  q->wrapuptime = 0;
1891  q->penaltymemberslimit = 0;
1892  q->joinempty = 0;
1893  q->leavewhenempty = 0;
1894  q->memberdelay = 0;
1895  q->maskmemberstatus = 0;
1896  q->eventwhencalled = 0;
1897  q->weight = 0;
1898  q->timeoutrestart = 0;
1900  q->randomperiodicannounce = 0;
1901  q->numperiodicannounce = 0;
1904  if (!q->members) {
1906  /* linear strategy depends on order, so we have to place all members in a single bucket */
1908  else
1910  }
1911  q->found = 1;
1912 
1913  ast_string_field_set(q, sound_next, "queue-youarenext");
1914  ast_string_field_set(q, sound_thereare, "queue-thereare");
1915  ast_string_field_set(q, sound_calls, "queue-callswaiting");
1916  ast_string_field_set(q, queue_quantity1, "queue-quantity1");
1917  ast_string_field_set(q, queue_quantity2, "queue-quantity2");
1918  ast_string_field_set(q, sound_holdtime, "queue-holdtime");
1919  ast_string_field_set(q, sound_minutes, "queue-minutes");
1920  ast_string_field_set(q, sound_minute, "queue-minute");
1921  ast_string_field_set(q, sound_seconds, "queue-seconds");
1922  ast_string_field_set(q, sound_thanks, "queue-thankyou");
1923  ast_string_field_set(q, sound_reporthold, "queue-reporthold");
1924 
1925  if (!q->sound_periodicannounce[0]) {
1927  }
1928 
1929  if (q->sound_periodicannounce[0]) {
1930  ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
1931  }
1932 
1933  for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
1934  if (q->sound_periodicannounce[i])
1935  ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
1936  }
1937 
1938  while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list)))
1939  ast_free(pr_iter);
1940 }
1941 
1942 static void clear_queue(struct call_queue *q)
1944  q->holdtime = 0;
1945  q->callscompleted = 0;
1946  q->callsabandoned = 0;
1947  q->callscompletedinsl = 0;
1948  q->talktime = 0;
1949 
1950  if (q->members) {
1951  struct member *mem;
1952  struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
1953  while ((mem = ao2_iterator_next(&mem_iter))) {
1954  mem->calls = 0;
1955  mem->lastcall = 0;
1956  ao2_ref(mem, -1);
1957  }
1958  ao2_iterator_destroy(&mem_iter);
1959  }
1960 }
1961 
1962 /*!
1963  * \brief Change queue penalty by adding rule.
1964  *
1965  * Check rule for errors with time or fomatting, see if rule is relative to rest
1966  * of queue, iterate list of rules to find correct insertion point, insert and return.
1967  * \retval -1 on failure
1968  * \retval 0 on success
1969  * \note Call this with the rule_lists locked
1970 */
1971 static int insert_penaltychange(const char *list_name, const char *content, const int linenum)
1973  char *timestr, *maxstr, *minstr, *contentdup;
1974  struct penalty_rule *rule = NULL, *rule_iter;
1975  struct rule_list *rl_iter;
1976  int penaltychangetime, inserted = 0;
1977 
1978  if (!(rule = ast_calloc(1, sizeof(*rule)))) {
1979  return -1;
1980  }
1981 
1982  contentdup = ast_strdupa(content);
1983 
1984  if (!(maxstr = strchr(contentdup, ','))) {
1985  ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum);
1986  ast_free(rule);
1987  return -1;
1988  }
1989 
1990  *maxstr++ = '\0';
1991  timestr = contentdup;
1992 
1993  if ((penaltychangetime = atoi(timestr)) < 0) {
1994  ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum);
1995  ast_free(rule);
1996  return -1;
1997  }
1998 
1999  rule->time = penaltychangetime;
2000 
2001  if ((minstr = strchr(maxstr,',')))
2002  *minstr++ = '\0';
2003 
2004  /* The last check will evaluate true if either no penalty change is indicated for a given rule
2005  * OR if a min penalty change is indicated but no max penalty change is */
2006  if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') {
2007  rule->max_relative = 1;
2008  }
2009 
2010  rule->max_value = atoi(maxstr);
2011 
2012  if (!ast_strlen_zero(minstr)) {
2013  if (*minstr == '+' || *minstr == '-')
2014  rule->min_relative = 1;
2015  rule->min_value = atoi(minstr);
2016  } else /*there was no minimum specified, so assume this means no change*/
2017  rule->min_relative = 1;
2018 
2019  /*We have the rule made, now we need to insert it where it belongs*/
2020  AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){
2021  if (strcasecmp(rl_iter->name, list_name))
2022  continue;
2023 
2024  AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) {
2025  if (rule->time < rule_iter->time) {
2026  AST_LIST_INSERT_BEFORE_CURRENT(rule, list);
2027  inserted = 1;
2028  break;
2029  }
2030  }
2032 
2033  if (!inserted) {
2034  AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list);
2035  inserted = 1;
2036  }
2037 
2038  break;
2039  }
2040 
2041  if (!inserted) {
2042  ast_log(LOG_WARNING, "Unknown rule list name %s; ignoring.\n", list_name);
2043  ast_free(rule);
2044  return -1;
2045  }
2046  return 0;
2047 }
2048 
2049 static void parse_empty_options(const char *value, enum empty_conditions *empty, int joinempty)
2051  char *value_copy = ast_strdupa(value);
2052  char *option = NULL;
2053  while ((option = strsep(&value_copy, ","))) {
2054  if (!strcasecmp(option, "paused")) {
2055  *empty |= QUEUE_EMPTY_PAUSED;
2056  } else if (!strcasecmp(option, "penalty")) {
2057  *empty |= QUEUE_EMPTY_PENALTY;
2058  } else if (!strcasecmp(option, "inuse")) {
2059  *empty |= QUEUE_EMPTY_INUSE;
2060  } else if (!strcasecmp(option, "ringing")) {
2061  *empty |= QUEUE_EMPTY_RINGING;
2062  } else if (!strcasecmp(option, "invalid")) {
2063  *empty |= QUEUE_EMPTY_INVALID;
2064  } else if (!strcasecmp(option, "wrapup")) {
2065  *empty |= QUEUE_EMPTY_WRAPUP;
2066  } else if (!strcasecmp(option, "unavailable")) {
2067  *empty |= QUEUE_EMPTY_UNAVAILABLE;
2068  } else if (!strcasecmp(option, "unknown")) {
2069  *empty |= QUEUE_EMPTY_UNKNOWN;
2070  } else if (!strcasecmp(option, "loose")) {
2072  } else if (!strcasecmp(option, "strict")) {
2074  } else if ((ast_false(option) && joinempty) || (ast_true(option) && !joinempty)) {
2076  } else if ((ast_false(option) && !joinempty) || (ast_true(option) && joinempty)) {
2077  *empty = 0;
2078  } else {
2079  ast_log(LOG_WARNING, "Unknown option %s for '%s'\n", option, joinempty ? "joinempty" : "leavewhenempty");
2080  }
2081  }
2082 }
2083 
2084 /*! \brief Configure a queue parameter.
2085  *
2086  * The failunknown flag is set for config files (and static realtime) to show
2087  * errors for unknown parameters. It is cleared for dynamic realtime to allow
2088  * extra fields in the tables.
2089  * \note For error reporting, line number is passed for .conf static configuration,
2090  * for Realtime queues, linenum is -1.
2091 */
2092 static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
2094  if (!strcasecmp(param, "musicclass") ||
2095  !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
2096  ast_string_field_set(q, moh, val);
2097  } else if (!strcasecmp(param, "announce")) {
2098  ast_string_field_set(q, announce, val);
2099  } else if (!strcasecmp(param, "context")) {
2100  ast_string_field_set(q, context, val);
2101  } else if (!strcasecmp(param, "timeout")) {
2102  q->timeout = atoi(val);
2103  if (q->timeout < 0)
2104  q->timeout = DEFAULT_TIMEOUT;
2105  } else if (!strcasecmp(param, "ringinuse")) {
2106  q->ringinuse = ast_true(val);
2107  } else if (!strcasecmp(param, "setinterfacevar")) {
2108  q->setinterfacevar = ast_true(val);
2109  } else if (!strcasecmp(param, "setqueuevar")) {
2110  q->setqueuevar = ast_true(val);
2111  } else if (!strcasecmp(param, "setqueueentryvar")) {
2112  q->setqueueentryvar = ast_true(val);
2113  } else if (!strcasecmp(param, "monitor-format")) {
2114  ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
2115  } else if (!strcasecmp(param, "membermacro")) {
2116  ast_string_field_set(q, membermacro, val);
2117  } else if (!strcasecmp(param, "membergosub")) {
2118  ast_string_field_set(q, membergosub, val);
2119  } else if (!strcasecmp(param, "queue-youarenext")) {
2120  ast_string_field_set(q, sound_next, val);
2121  } else if (!strcasecmp(param, "queue-thereare")) {
2122  ast_string_field_set(q, sound_thereare, val);
2123  } else if (!strcasecmp(param, "queue-callswaiting")) {
2124  ast_string_field_set(q, sound_calls, val);
2125  } else if (!strcasecmp(param, "queue-quantity1")) {
2126  ast_string_field_set(q, queue_quantity1, val);
2127  } else if (!strcasecmp(param, "queue-quantity2")) {
2128  ast_string_field_set(q, queue_quantity2, val);
2129  } else if (!strcasecmp(param, "queue-holdtime")) {
2130  ast_string_field_set(q, sound_holdtime, val);
2131  } else if (!strcasecmp(param, "queue-minutes")) {
2132  ast_string_field_set(q, sound_minutes, val);
2133  } else if (!strcasecmp(param, "queue-minute")) {
2134  ast_string_field_set(q, sound_minute, val);
2135  } else if (!strcasecmp(param, "queue-seconds")) {
2136  ast_string_field_set(q, sound_seconds, val);
2137  } else if (!strcasecmp(param, "queue-thankyou")) {
2138  ast_string_field_set(q, sound_thanks, val);
2139  } else if (!strcasecmp(param, "queue-callerannounce")) {
2140  ast_string_field_set(q, sound_callerannounce, val);
2141  } else if (!strcasecmp(param, "queue-reporthold")) {
2142  ast_string_field_set(q, sound_reporthold, val);
2143  } else if (!strcasecmp(param, "announce-frequency")) {
2144  q->announcefrequency = atoi(val);
2145  } else if (!strcasecmp(param, "announce-to-first-user")) {
2146  q->announce_to_first_user = ast_true(val);
2147  } else if (!strcasecmp(param, "min-announce-frequency")) {
2148  q->minannouncefrequency = atoi(val);
2149  ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name);
2150  } else if (!strcasecmp(param, "announce-round-seconds")) {
2151  q->roundingseconds = atoi(val);
2152  /* Rounding to any other values just doesn't make sense... */
2153  if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10
2154  || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) {
2155  if (linenum >= 0) {
2156  ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
2157  "using 0 instead for queue '%s' at line %d of queues.conf\n",
2158  val, param, q->name, linenum);
2159  } else {
2160  ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
2161  "using 0 instead for queue '%s'\n", val, param, q->name);
2162  }
2163  q->roundingseconds=0;
2164  }
2165  } else if (!strcasecmp(param, "announce-holdtime")) {
2166  if (!strcasecmp(val, "once"))
2168  else if (ast_true(val))
2170  else
2171  q->announceholdtime = 0;
2172  } else if (!strcasecmp(param, "announce-position")) {
2173  if (!strcasecmp(val, "limit"))
2175  else if (!strcasecmp(val, "more"))
2177  else if (ast_true(val))
2179  else
2181  } else if (!strcasecmp(param, "announce-position-limit")) {
2182  q->announcepositionlimit = atoi(val);
2183  } else if (!strcasecmp(param, "periodic-announce")) {
2184  if (strchr(val, ',')) {
2185  char *s, *buf = ast_strdupa(val);
2186  unsigned int i = 0;
2187 
2188  while ((s = strsep(&buf, ",|"))) {
2189  if (!q->sound_periodicannounce[i])
2191  ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s);
2192  i++;
2193  if (i == MAX_PERIODIC_ANNOUNCEMENTS)
2194  break;
2195  }
2196  q->numperiodicannounce = i;
2197  } else {
2198  ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val);
2199  q->numperiodicannounce = 1;
2200  }
2201  } else if (!strcasecmp(param, "periodic-announce-frequency")) {
2202  q->periodicannouncefrequency = atoi(val);
2203  } else if (!strcasecmp(param, "relative-periodic-announce")) {
2205  } else if (!strcasecmp(param, "random-periodic-announce")) {
2206  q->randomperiodicannounce = ast_true(val);
2207  } else if (!strcasecmp(param, "retry")) {
2208  q->retry = atoi(val);
2209  if (q->retry <= 0)
2210  q->retry = DEFAULT_RETRY;
2211  } else if (!strcasecmp(param, "wrapuptime")) {
2212  q->wrapuptime = atoi(val);
2213  } else if (!strcasecmp(param, "penaltymemberslimit")) {
2214  if ((sscanf(val, "%10d", &q->penaltymemberslimit) != 1)) {
2215  q->penaltymemberslimit = 0;
2216  }
2217  } else if (!strcasecmp(param, "autofill")) {
2218  q->autofill = ast_true(val);
2219  } else if (!strcasecmp(param, "monitor-type")) {
2220  if (!strcasecmp(val, "mixmonitor"))
2221  q->montype = 1;
2222  } else if (!strcasecmp(param, "autopause")) {
2223  q->autopause = autopause2int(val);
2224  } else if (!strcasecmp(param, "maxlen")) {
2225  q->maxlen = atoi(val);
2226  if (q->maxlen < 0)
2227  q->maxlen = 0;
2228  } else if (!strcasecmp(param, "ringlimit")) {
2229  q->ringlimit = atoi(val);
2230  if (q->ringlimit < 0)
2231  q->ringlimit = 0;
2232  } else if (!strcasecmp(param, "servicelevel")) {
2233  q->servicelevel= atoi(val);
2234  } else if (!strcasecmp(param, "strategy")) {
2235  int strategy;
2236 
2237  /* We are a static queue and already have set this, no need to do it again */
2238  if (failunknown) {
2239  return;
2240  }
2241  strategy = strat2int(val);
2242  if (strategy < 0) {
2243  ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
2244  val, q->name);
2246  }
2247  if (strategy == q->strategy) {
2248  return;
2249  }
2250  if (strategy == QUEUE_STRATEGY_LINEAR) {
2251  ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n");
2252  return;
2253  }
2254  q->strategy = strategy;
2255  } else if (!strcasecmp(param, "joinempty")) {
2256  parse_empty_options(val, &q->joinempty, 1);
2257  } else if (!strcasecmp(param, "leavewhenempty")) {
2258  parse_empty_options(val, &q->leavewhenempty, 0);
2259  } else if (!strcasecmp(param, "eventmemberstatus")) {
2260  q->maskmemberstatus = !ast_true(val);
2261  } else if (!strcasecmp(param, "eventwhencalled")) {
2262  if (!strcasecmp(val, "vars")) {
2264  } else {
2265  q->eventwhencalled = ast_true(val) ? 1 : 0;
2266  }
2267  } else if (!strcasecmp(param, "reportholdtime")) {
2268  q->reportholdtime = ast_true(val);
2269  } else if (!strcasecmp(param, "memberdelay")) {
2270  q->memberdelay = atoi(val);
2271  } else if (!strcasecmp(param, "weight")) {
2272  q->weight = atoi(val);
2273  } else if (!strcasecmp(param, "timeoutrestart")) {
2274  q->timeoutrestart = ast_true(val);
2275  } else if (!strcasecmp(param, "defaultrule")) {
2276  ast_string_field_set(q, defaultrule, val);
2277  } else if (!strcasecmp(param, "timeoutpriority")) {
2278  if (!strcasecmp(val, "conf")) {
2280  } else {
2282  }
2283  } else if (failunknown) {
2284  if (linenum >= 0) {
2285  ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
2286  q->name, param, linenum);
2287  } else {
2288  ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
2289  }
2290  }
2291 }
2292 
2293 /*! \internal
2294  * \brief If adding a single new member to a queue, use this function instead of ao2_linking.
2295  * This adds round robin queue position data for a fresh member as well as links it.
2296  * \param queue Which queue the member is being added to
2297  * \param mem Which member is being added to the queue
2298  */
2299 static void member_add_to_queue(struct call_queue *queue, struct member *mem)
2301  ao2_lock(queue->members);
2302  mem->queuepos = ao2_container_count(queue->members);
2303  ao2_link(queue->members, mem);
2304  ao2_unlock(queue->members);
2305 }
2306 
2307 /*! \internal
2308  * \brief If removing a single member from a queue, use this function instead of ao2_unlinking.
2309  * This will perform round robin queue position reordering for the remaining members.
2310  * \param queue Which queue the member is being removed from
2311  * \param member Which member is being removed from the queue
2312  */
2313 static void member_remove_from_queue(struct call_queue *queue, struct member *mem)
2315  ao2_lock(queue->members);
2316  queue_member_follower_removal(queue, mem);
2317  ao2_unlink(queue->members, mem);
2318  ao2_unlock(queue->members);
2319 }
2320 
2321 /*!
2322  * \brief Find rt member record to update otherwise create one.
2323  *
2324  * Search for member in queue, if found update penalty/paused state,
2325  * if no member exists create one flag it as a RT member and add to queue member list.
2326 */
2327 static void rt_handle_member_record(struct call_queue *q, char *interface, const char *rt_uniqueid, const char *membername, const char *penalty_str, const char *paused_str, const char* state_interface)
2329  struct member *m;
2330  struct ao2_iterator mem_iter;
2331  int penalty = 0;
2332  int paused = 0;
2333  int found = 0;
2334 
2335  if (ast_strlen_zero(rt_uniqueid)) {
2336  ast_log(LOG_WARNING, "Realtime field uniqueid is empty for member %s\n", S_OR(membername, "NULL"));
2337  return;
2338  }
2339 
2340  if (penalty_str) {
2341  penalty = atoi(penalty_str);
2342  if (penalty < 0)
2343  penalty = 0;
2344  }
2345 
2346  if (paused_str) {
2347  paused = atoi(paused_str);
2348  if (paused < 0)
2349  paused = 0;
2350  }
2351 
2352  /* Find member by realtime uniqueid and update */
2353  mem_iter = ao2_iterator_init(q->members, 0);
2354  while ((m = ao2_iterator_next(&mem_iter))) {
2355  if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) {
2356  m->dead = 0; /* Do not delete this one. */
2357  ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
2358  if (paused_str)
2359  m->paused = paused;
2360  if (strcasecmp(state_interface, m->state_interface)) {
2361  ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
2362  }
2363  m->penalty = penalty;
2364  found = 1;
2365  ao2_ref(m, -1);
2366  break;
2367  }
2368  ao2_ref(m, -1);
2369  }
2370  ao2_iterator_destroy(&mem_iter);
2371 
2372  /* Create a new member */
2373  if (!found) {
2374  if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) {
2375  m->dead = 0;
2376  m->realtime = 1;
2377  ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
2378  ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
2379  member_add_to_queue(q, m);
2380  ao2_ref(m, -1);
2381  m = NULL;
2382  }
2383  }
2384 }
2385 
2386 /*! \brief Iterate through queue's member list and delete them */
2387 static void free_members(struct call_queue *q, int all)
2389  /* Free non-dynamic members */
2390  struct member *cur;
2391  struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
2392 
2393  while ((cur = ao2_iterator_next(&mem_iter))) {
2394  if (all || !cur->dynamic) {
2395  member_remove_from_queue(q, cur);
2396  }
2397  ao2_ref(cur, -1);
2398  }
2399  ao2_iterator_destroy(&mem_iter);
2400 }
2401 
2402 /*! \brief Free queue's member list then its string fields */
2403 static void destroy_queue(void *obj)
2405  struct call_queue *q = obj;
2406  int i;
2407 
2408  free_members(q, 1);
2410  for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
2411  if (q->sound_periodicannounce[i])
2413  }
2414  ao2_ref(q->members, -1);
2415 }
2416 
2417 static struct call_queue *alloc_queue(const char *queuename)
2419  struct call_queue *q;
2420 
2421  if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) {
2422  if (ast_string_field_init(q, 64)) {
2423  queue_t_unref(q, "String field allocation failed");
2424  return NULL;
2425  }
2426  ast_string_field_set(q, name, queuename);
2427  }
2428  return q;
2429 }
2430 
2431 /*!
2432  * \brief Reload a single queue via realtime.
2433  *
2434  * Check for statically defined queue first, check if deleted RT queue,
2435  * check for new RT queue, if queue vars are not defined init them with defaults.
2436  * reload RT queue vars, set RT queue members dead and reload them, return finished queue.
2437  * \retval the queue,
2438  * \retval NULL if it doesn't exist.
2439  * \note Should be called with the "queues" container locked.
2440 */
2441 static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
2443  struct ast_variable *v;
2444  struct call_queue *q, tmpq = {
2445  .name = queuename,
2446  };
2447  struct member *m;
2448  struct ao2_iterator mem_iter;
2449  char *interface = NULL;
2450  const char *tmp_name;
2451  char *tmp;
2452  char tmpbuf[64]; /* Must be longer than the longest queue param name. */
2453 
2454  /* Static queues override realtime. */
2455  if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Check if static queue exists"))) {
2456  ao2_lock(q);
2457  if (!q->realtime) {
2458  if (q->dead) {
2459  ao2_unlock(q);
2460  queue_t_unref(q, "Queue is dead; can't return it");
2461  return NULL;
2462  } else {
2463  ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
2464  ao2_unlock(q);
2465  return q;
2466  }
2467  }
2468  } else if (!member_config)
2469  /* Not found in the list, and it's not realtime ... */
2470  return NULL;
2471 
2472  /* Check if queue is defined in realtime. */
2473  if (!queue_vars) {
2474  /* Delete queue from in-core list if it has been deleted in realtime. */
2475  if (q) {
2476  /*! \note Hmm, can't seem to distinguish a DB failure from a not
2477  found condition... So we might delete an in-core queue
2478  in case of DB failure. */
2479  ast_debug(1, "Queue %s not found in realtime.\n", queuename);
2480 
2481  q->dead = 1;
2482  /* Delete if unused (else will be deleted when last caller leaves). */
2483  queues_t_unlink(queues, q, "Unused; removing from container");
2484  ao2_unlock(q);
2485  queue_t_unref(q, "Queue is dead; can't return it");
2486  }
2487  return NULL;
2488  }
2489 
2490  /* Create a new queue if an in-core entry does not exist yet. */
2491  if (!q) {
2492  struct ast_variable *tmpvar = NULL;
2493  if (!(q = alloc_queue(queuename)))
2494  return NULL;
2495  ao2_lock(q);
2496  clear_queue(q);
2497  q->realtime = 1;
2498  /*Before we initialize the queue, we need to set the strategy, so that linear strategy
2499  * will allocate the members properly
2500  */
2501  for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) {
2502  if (!strcasecmp(tmpvar->name, "strategy")) {
2503  q->strategy = strat2int(tmpvar->value);
2504  if (q->strategy < 0) {
2505  ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
2506  tmpvar->value, q->name);
2508  }
2509  break;
2510  }
2511  }
2512  /* We traversed all variables and didn't find a strategy */
2513  if (!tmpvar)
2515  queues_t_link(queues, q, "Add queue to container");
2516  }
2517  init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
2518 
2519  memset(tmpbuf, 0, sizeof(tmpbuf));
2520  for (v = queue_vars; v; v = v->next) {
2521  /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
2522  if (strchr(v->name, '_')) {
2523  ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
2524  tmp_name = tmpbuf;
2525  tmp = tmpbuf;
2526  while ((tmp = strchr(tmp, '_')))
2527  *tmp++ = '-';
2528  } else
2529  tmp_name = v->name;
2530 
2531  /* NULL values don't get returned from realtime; blank values should
2532  * still get set. If someone doesn't want a value to be set, they
2533  * should set the realtime column to NULL, not blank. */
2534  queue_set_param(q, tmp_name, v->value, -1, 0);
2535  }
2536 
2537  /* Temporarily set realtime members dead so we can detect deleted ones. */
2538  mem_iter = ao2_iterator_init(q->members, 0);
2539  while ((m = ao2_iterator_next(&mem_iter))) {
2540  if (m->realtime)
2541  m->dead = 1;
2542  ao2_ref(m, -1);
2543  }
2544  ao2_iterator_destroy(&mem_iter);
2545 
2546  while ((interface = ast_category_browse(member_config, interface))) {
2547  rt_handle_member_record(q, interface,
2548  ast_variable_retrieve(member_config, interface, "uniqueid"),
2549  S_OR(ast_variable_retrieve(member_config, interface, "membername"),interface),
2550  ast_variable_retrieve(member_config, interface, "penalty"),
2551  ast_variable_retrieve(member_config, interface, "paused"),
2552  S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface));
2553  }
2554 
2555  /* Delete all realtime members that have been deleted in DB. */
2556  mem_iter = ao2_iterator_init(q->members, 0);
2557  while ((m = ao2_iterator_next(&mem_iter))) {
2558  if (m->dead) {
2559  ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
2561  }
2562  ao2_ref(m, -1);
2563  }
2564  ao2_iterator_destroy(&mem_iter);
2565 
2566  ao2_unlock(q);
2567 
2568  return q;
2569 }
2570 
2571 /*! \note Returns a reference to the loaded realtime queue. */
2572 static struct call_queue *load_realtime_queue(const char *queuename)
2574  struct ast_variable *queue_vars;
2575  struct ast_config *member_config = NULL;
2576  struct call_queue *q = NULL, tmpq = {
2577  .name = queuename,
2578  };
2579  int prev_weight = 0;
2580 
2581  /* Find the queue in the in-core list first. */
2582  q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Look for queue in memory first");
2583 
2584  if (!q || q->realtime) {
2585  /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all
2586  queue operations while waiting for the DB.
2587 
2588  This will be two separate database transactions, so we might
2589  see queue parameters as they were before another process
2590  changed the queue and member list as it was after the change.
2591  Thus we might see an empty member list when a queue is
2592  deleted. In practise, this is unlikely to cause a problem. */
2593 
2594  queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL);
2595  if (queue_vars) {
2596  member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL);
2597  if (!member_config) {
2598  ast_debug(1, "No queue_members defined in config extconfig.conf\n");
2599  member_config = ast_config_new();
2600  }
2601  }
2602  if (q) {
2603  prev_weight = q->weight ? 1 : 0;
2604  queue_t_unref(q, "Need to find realtime queue");
2605  }
2606 
2607  q = find_queue_by_name_rt(queuename, queue_vars, member_config);
2608  ast_config_destroy(member_config);
2609  ast_variables_destroy(queue_vars);
2610 
2611  /* update the use_weight value if the queue's has gained or lost a weight */
2612  if (q) {
2613  if (!q->weight && prev_weight) {
2614  ast_atomic_fetchadd_int(&use_weight, -1);
2615  }
2616  if (q->weight && !prev_weight) {
2617  ast_atomic_fetchadd_int(&use_weight, +1);
2618  }
2619  }
2620  /* Other cases will end up with the proper value for use_weight */
2621  } else {
2623  }
2624  return q;
2625 }
2626 
2627 static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
2629  int ret = -1;
2630 
2631  if (ast_strlen_zero(mem->rt_uniqueid))
2632  return ret;
2633 
2634  if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) > 0)
2635  ret = 0;
2636 
2637  return ret;
2638 }
2639 
2640 
2641 static void update_realtime_members(struct call_queue *q)
2643  struct ast_config *member_config = NULL;
2644  struct member *m;
2645  char *interface = NULL;
2646  struct ao2_iterator mem_iter;
2647 
2648  if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , SENTINEL))) {
2649  /* This queue doesn't have realtime members. If the queue still has any realtime
2650  * members in memory, they need to be removed.
2651  */
2652  ao2_lock(q);
2653  mem_iter = ao2_iterator_init(q->members, 0);
2654  while ((m = ao2_iterator_next(&mem_iter))) {
2655  if (m->realtime) {
2657  }
2658  ao2_ref(m, -1);
2659  }
2660  ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name);
2661  ao2_unlock(q);
2662  return;
2663  }
2664 
2665  ao2_lock(q);
2666 
2667  /* Temporarily set realtime members dead so we can detect deleted ones.*/
2668  mem_iter = ao2_iterator_init(q->members, 0);
2669  while ((m = ao2_iterator_next(&mem_iter))) {
2670  if (m->realtime)
2671  m->dead = 1;
2672  ao2_ref(m, -1);
2673  }
2674  ao2_iterator_destroy(&mem_iter);
2675 
2676  while ((interface = ast_category_browse(member_config, interface))) {
2677  rt_handle_member_record(q, interface,
2678  ast_variable_retrieve(member_config, interface, "uniqueid"),
2679  S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
2680  ast_variable_retrieve(member_config, interface, "penalty"),
2681  ast_variable_retrieve(member_config, interface, "paused"),
2682  S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface));
2683  }
2684 
2685  /* Delete all realtime members that have been deleted in DB. */
2686  mem_iter = ao2_iterator_init(q->members, 0);
2687  while ((m = ao2_iterator_next(&mem_iter))) {
2688  if (m->dead) {
2689  ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
2691  }
2692  ao2_ref(m, -1);
2693  }
2694  ao2_iterator_destroy(&mem_iter);
2695  ao2_unlock(q);
2696  ast_config_destroy(member_config);
2697 }
2698 
2699 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
2701  struct call_queue *q;
2702  struct queue_ent *cur, *prev = NULL;
2703  int res = -1;
2704  int pos = 0;
2705  int inserted = 0;
2706 
2707  if (!(q = load_realtime_queue(queuename)))
2708  return res;
2709 
2710  ao2_lock(q);
2711 
2712  /* This is our one */
2713  if (q->joinempty) {
2714  int status = 0;
2715  if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, q->joinempty, 0))) {
2716  *reason = QUEUE_JOINEMPTY;
2717  ao2_unlock(q);
2718  queue_t_unref(q, "Done with realtime queue");
2719  return res;
2720  }
2721  }
2722  if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen))
2723  *reason = QUEUE_FULL;
2724  else if (*reason == QUEUE_UNKNOWN) {
2725  /* There's space for us, put us at the right position inside
2726  * the queue.
2727  * Take into account the priority of the calling user */
2728  inserted = 0;
2729  prev = NULL;
2730  cur = q->head;
2731  while (cur) {
2732  /* We have higher priority than the current user, enter
2733  * before him, after all the other users with priority
2734  * higher or equal to our priority. */
2735  if ((!inserted) && (qe->prio > cur->prio)) {
2736  insert_entry(q, prev, qe, &pos);
2737  inserted = 1;
2738  }
2739  /* <= is necessary for the position comparison because it may not be possible to enter
2740  * at our desired position since higher-priority callers may have taken the position we want
2741  */
2742  if (!inserted && (qe->prio >= cur->prio) && position && (position <= pos + 1)) {
2743  insert_entry(q, prev, qe, &pos);
2744  inserted = 1;
2745  /*pos is incremented inside insert_entry, so don't need to add 1 here*/
2746  if (position < pos) {
2747  ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos);
2748  }
2749  }
2750  cur->pos = ++pos;
2751  prev = cur;
2752  cur = cur->next;
2753  }
2754  /* No luck, join at the end of the queue */
2755  if (!inserted)
2756  insert_entry(q, prev, qe, &pos);
2757  ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
2758  ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
2759  ast_copy_string(qe->context, q->context, sizeof(qe->context));
2760  q->count++;
2761  res = 0;
2762  ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Join",
2763  "Channel: %s\r\n"
2764  "CallerIDNum: %s\r\n"
2765  "CallerIDName: %s\r\n"
2766  "ConnectedLineNum: %s\r\n"
2767  "ConnectedLineName: %s\r\n"
2768  "Queue: %s\r\n"
2769  "Position: %d\r\n"
2770  "Count: %d\r\n"
2771  "Uniqueid: %s\r\n",
2772  qe->chan->name,
2773  S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"),/* XXX somewhere else it is <unknown> */
2774  S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"),
2775  S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"),/* XXX somewhere else it is <unknown> */
2776  S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"),
2777  q->name, qe->pos, q->count, qe->chan->uniqueid );
2778  ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
2779  }
2780  ao2_unlock(q);
2781  queue_t_unref(q, "Done with realtime queue");
2782 
2783  return res;
2784 }
2785 
2786 static int play_file(struct ast_channel *chan, const char *filename)
2788  int res;
2789 
2790  if (ast_strlen_zero(filename)) {
2791  return 0;
2792  }
2793 
2794  if (!ast_fileexists(filename, NULL, chan->language)) {
2795  return 0;
2796  }
2797 
2798  ast_stopstream(chan);
2799 
2800  res = ast_streamfile(chan, filename, chan->language);
2801  if (!res)
2802  res = ast_waitstream(chan, AST_DIGIT_ANY);
2803 
2804  ast_stopstream(chan);
2805 
2806  return res;
2807 }
2808 
2809 /*!
2810  * \brief Check for valid exit from queue via goto
2811  * \retval 0 if failure
2812  * \retval 1 if successful
2813 */
2814 static int valid_exit(struct queue_ent *qe, char digit)
2816  int digitlen = strlen(qe->digits);
2817 
2818  /* Prevent possible buffer overflow */
2819  if (digitlen < sizeof(qe->digits) - 2) {
2820  qe->digits[digitlen] = digit;
2821  qe->digits[digitlen + 1] = '\0';
2822  } else {
2823  qe->digits[0] = '\0';
2824  return 0;
2825  }
2826 
2827  /* If there's no context to goto, short-circuit */
2828  if (ast_strlen_zero(qe->context))
2829  return 0;
2830 
2831  /* If the extension is bad, then reset the digits to blank */
2832  if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1,
2833  S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, NULL))) {
2834  qe->digits[0] = '\0';
2835  return 0;
2836  }
2837 
2838  /* We have an exact match */
2839  if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
2840  qe->valid_digits = 1;
2841  /* Return 1 on a successful goto */
2842  return 1;
2843  }
2844 
2845  return 0;
2846 }
2847 
2848 static int say_position(struct queue_ent *qe, int ringing)
2850  int res = 0, avgholdmins, avgholdsecs, announceposition = 0;
2851  int say_thanks = 1;
2852  time_t now;
2853 
2854  /* Let minannouncefrequency seconds pass between the start of each position announcement */
2855  time(&now);
2856  if ((now - qe->last_pos) < qe->parent->minannouncefrequency)
2857  return 0;
2858 
2859  /* If either our position has changed, or we are over the freq timer, say position */
2860  if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency))
2861  return 0;
2862 
2863  if (ringing) {
2864  ast_indicate(qe->chan,-1);
2865  } else {
2866  ast_moh_stop(qe->chan);
2867  }
2868 
2872  qe->pos <= qe->parent->announcepositionlimit))
2873  announceposition = 1;
2874 
2875 
2876  if (announceposition == 1) {
2877  /* Say we're next, if we are */
2878  if (qe->pos == 1) {
2879  res = play_file(qe->chan, qe->parent->sound_next);
2880  if (res)
2881  goto playout;
2882  else
2883  goto posout;
2884  } else {
2886  /* More than Case*/
2887  res = play_file(qe->chan, qe->parent->queue_quantity1);
2888  if (res)
2889  goto playout;
2890  res = ast_say_number(qe->chan, qe->parent->announcepositionlimit, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */
2891  if (res)
2892  goto playout;
2893  } else {
2894  /* Normal Case */
2895  res = play_file(qe->chan, qe->parent->sound_thereare);
2896  if (res)
2897  goto playout;
2898  res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */
2899  if (res)
2900  goto playout;
2901  }
2903  /* More than Case*/
2904  res = play_file(qe->chan, qe->parent->queue_quantity2);
2905  if (res)
2906  goto playout;
2907  } else {
2908  res = play_file(qe->chan, qe->parent->sound_calls);
2909  if (res)
2910  goto playout;
2911  }
2912  }
2913  }
2914  /* Round hold time to nearest minute */
2915  avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
2916 
2917  /* If they have specified a rounding then round the seconds as well */
2918  if (qe->parent->roundingseconds) {
2919  avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
2920  avgholdsecs *= qe->parent->roundingseconds;
2921  } else {
2922  avgholdsecs = 0;
2923  }
2924 
2925  ast_verb(3, "Hold time for %s is %d minute(s) %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
2926 
2927  /* If the hold time is >1 min, if it's enabled, and if it's not
2928  supposed to be only once and we have already said it, say it */
2929  if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime &&
2932  res = play_file(qe->chan, qe->parent->sound_holdtime);
2933  if (res)
2934  goto playout;
2935 
2936  if (avgholdmins >= 1) {
2937  res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL);
2938  if (res)
2939  goto playout;
2940 
2941  if (avgholdmins == 1) {
2942  res = play_file(qe->chan, qe->parent->sound_minute);
2943  if (res)
2944  goto playout;
2945  } else {
2946  res = play_file(qe->chan, qe->parent->sound_minutes);
2947  if (res)
2948  goto playout;
2949  }
2950  }
2951  if (avgholdsecs >= 1) {
2952  res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL);
2953  if (res)
2954  goto playout;
2955 
2956  res = play_file(qe->chan, qe->parent->sound_seconds);
2957  if (res)
2958  goto playout;
2959  }
2960  } else if (qe->parent->announceholdtime && !qe->parent->announceposition) {
2961  say_thanks = 0;
2962  }
2963 
2964 posout:
2965  if (qe->parent->announceposition) {
2966  ast_verb(3, "Told %s in %s their queue position (which was %d)\n",
2967  qe->chan->name, qe->parent->name, qe->pos);
2968  }
2969  if (say_thanks) {
2970  res = play_file(qe->chan, qe->parent->sound_thanks);
2971  }
2972 playout:
2973 
2974  if ((res > 0 && !valid_exit(qe, res)))
2975  res = 0;
2976 
2977  /* Set our last_pos indicators */
2978  qe->last_pos = now;
2979  qe->last_pos_said = qe->pos;
2980 
2981  /* Don't restart music on hold if we're about to exit the caller from the queue */
2982  if (!res) {
2983  if (ringing) {
2985  } else {
2986  ast_moh_start(qe->chan, qe->moh, NULL);
2987  }
2988  }
2989  return res;
2990 }
2991 
2992 static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
2994  int oldvalue;
2995 
2996  /* Calculate holdtime using an exponential average */
2997  /* Thanks to SRT for this contribution */
2998  /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
2999 
3000  ao2_lock(qe->parent);
3001  oldvalue = qe->parent->holdtime;
3002  qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
3003  ao2_unlock(qe->parent);
3004 }
3005 
3006 /*! \brief Caller leaving queue.
3007  *
3008  * Search the queue to find the leaving client, if found remove from queue
3009  * create manager event, move others up the queue.
3010 */
3011 static void leave_queue(struct queue_ent *qe)
3013  struct call_queue *q;
3014  struct queue_ent *current, *prev = NULL;
3015  struct penalty_rule *pr_iter;
3016  int pos = 0;
3017 
3018  if (!(q = qe->parent))
3019  return;
3020  queue_t_ref(q, "Copy queue pointer from queue entry");
3021  ao2_lock(q);
3022 
3023  prev = NULL;
3024  for (current = q->head; current; current = current->next) {
3025  if (current == qe) {
3026  char posstr[20];
3027  q->count--;
3028 
3029  /* Take us out of the queue */
3030  ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Leave",
3031  "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nPosition: %d\r\nUniqueid: %s\r\n",
3032  qe->chan->name, q->name, q->count, qe->pos, qe->chan->uniqueid);
3033  ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
3034  /* Take us out of the queue */
3035  if (prev)
3036  prev->next = current->next;
3037  else
3038  q->head = current->next;
3039  /* Free penalty rules */
3040  while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list)))
3041  ast_free(pr_iter);
3042  snprintf(posstr, sizeof(posstr), "%d", qe->pos);
3043  pbx_builtin_setvar_helper(qe->chan, "QUEUEPOSITION", posstr);
3044  } else {
3045  /* Renumber the people after us in the queue based on a new count */
3046  current->pos = ++pos;
3047  prev = current;
3048  }
3049  }
3050  ao2_unlock(q);
3051 
3052  /*If the queue is a realtime queue, check to see if it's still defined in real time*/
3053  if (q->realtime) {
3054  struct ast_variable *var;
3055  if (!(var = ast_load_realtime("queues", "name", q->name, SENTINEL))) {
3056  q->dead = 1;
3057  } else {
3058  ast_variables_destroy(var);
3059  }
3060  }
3061 
3062  if (q->dead) {
3063  /* It's dead and nobody is in it, so kill it */
3064  queues_t_unlink(queues, q, "Queue is now dead; remove it from the container");
3065  }
3066  /* unref the explicit ref earlier in the function */
3067  queue_t_unref(q, "Expire copied reference");
3068 }
3069 
3070 /*!
3071  * \internal
3072  * \brief Destroy the given callattempt structure and free it.
3073  * \since 1.8
3074  *
3075  * \param doomed callattempt structure to destroy.
3076  *
3077  * \return Nothing
3078  */
3079 static void callattempt_free(struct callattempt *doomed)
3081  if (doomed->member) {
3082  ao2_ref(doomed->member, -1);
3083  }
3085  ast_free(doomed);
3086 }
3087 
3088 /*! \brief Hang up a list of outgoing calls */
3089 static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere)
3091  struct callattempt *oo;
3092 
3093  while (outgoing) {
3094  /* If someone else answered the call we should indicate this in the CANCEL */
3095  /* Hangup any existing lines we have open */
3096  if (outgoing->chan && (outgoing->chan != exception)) {
3097  if (exception || cancel_answered_elsewhere)
3099  ast_hangup(outgoing->chan);
3100  }
3101  oo = outgoing;
3102  outgoing = outgoing->q_next;
3104  callattempt_free(oo);
3105  }
3106 }
3107 
3108 /*!
3109  * \brief Get the number of members available to accept a call.
3110  *
3111  * \note The queue passed in should be locked prior to this function call
3112  *
3113  * \param[in] q The queue for which we are couting the number of available members
3114  * \return Return the number of available members in queue q
3115  */
3116 static int num_available_members(struct call_queue *q)
3118  struct member *mem;
3119  int avl = 0;
3120  struct ao2_iterator mem_iter;
3121 
3122  mem_iter = ao2_iterator_init(q->members, 0);
3123  while ((mem = ao2_iterator_next(&mem_iter))) {
3124  switch (mem->status) {
3125  case AST_DEVICE_INUSE:
3126  if (!q->ringinuse)
3127  break;
3128  /* else fall through */
3129  case AST_DEVICE_NOT_INUSE:
3130  case AST_DEVICE_ONHOLD:
3131  case AST_DEVICE_RINGINUSE:
3132  case AST_DEVICE_RINGING:
3133  case AST_DEVICE_UNKNOWN:
3134  if (!mem->paused) {
3135  avl++;
3136  }
3137  break;
3138  }
3139  ao2_ref(mem, -1);
3140 
3141  /* If autofill is not enabled or if the queue's strategy is ringall, then
3142  * we really don't care about the number of available members so much as we
3143  * do that there is at least one available.
3144  *
3145  * In fact, we purposely will return from this function stating that only
3146  * one member is available if either of those conditions hold. That way,
3147  * functions which determine what action to take based on the number of available
3148  * members will operate properly. The reasoning is that even if multiple
3149  * members are available, only the head caller can actually be serviced.
3150  */
3151  if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) {
3152  break;
3153  }
3154  }
3155  ao2_iterator_destroy(&mem_iter);
3156 
3157  return avl;
3158 }
3159 
3160 /* traverse all defined queues which have calls waiting and contain this member
3161  return 0 if no other queue has precedence (higher weight) or 1 if found */
3162 static int compare_weight(struct call_queue *rq, struct member *member)
3164  struct call_queue *q;
3165  struct member *mem;
3166  int found = 0;
3167  struct ao2_iterator queue_iter;
3168 
3169  queue_iter = ao2_iterator_init(queues, 0);
3170  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
3171  if (q == rq) { /* don't check myself, could deadlock */
3172  queue_t_unref(q, "Done with iterator");
3173  continue;
3174  }
3175  ao2_lock(q);
3176  if (q->count && q->members) {
3177  if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
3178  ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
3179  if (q->weight > rq->weight && q->count >= num_available_members(q)) {
3180  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);
3181  found = 1;
3182  }
3183  ao2_ref(mem, -1);
3184  }
3185  }
3186  ao2_unlock(q);
3187  queue_t_unref(q, "Done with iterator");
3188  if (found) {
3189  break;
3190  }
3191  }
3192  ao2_iterator_destroy(&queue_iter);
3193  return found;
3194 }
3195 
3196 /*! \brief common hangup actions */
3197 static void do_hang(struct callattempt *o)
3199  o->stillgoing = 0;
3200  ast_hangup(o->chan);
3201  o->chan = NULL;
3202 }
3203 
3204 /*! \brief convert "\n" to "\nVariable: " ready for manager to use */
3205 static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
3207  struct ast_str *buf = ast_str_thread_get(&ast_str_thread_global_buf, len + 1);
3208  const char *tmp;
3209 
3210  if (pbx_builtin_serialize_variables(chan, &buf)) {
3211  int i, j;
3212 
3213  /* convert "\n" to "\nVariable: " */
3214  strcpy(vars, "Variable: ");
3215  tmp = ast_str_buffer(buf);
3216 
3217  for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) {
3218  vars[j] = tmp[i];
3219 
3220  if (tmp[i + 1] == '\0')
3221  break;
3222  if (tmp[i] == '\n') {
3223  vars[j++] = '\r';
3224  vars[j++] = '\n';
3225 
3226  ast_copy_string(&(vars[j]), "Variable: ", len - j);
3227  j += 9;
3228  }
3229  }
3230  if (j > len - 3)
3231  j = len - 3;
3232  vars[j++] = '\r';
3233  vars[j++] = '\n';
3234  vars[j] = '\0';
3235  } else {
3236  /* there are no channel variables; leave it blank */
3237  *vars = '\0';
3238  }
3239  return vars;
3240 }
3241 
3242 /*!
3243  * \internal
3244  * \brief Check if the member status is available.
3245  *
3246  * \param status Member status to check if available.
3247  *
3248  * \retval non-zero if the member status is available.
3249  */
3250 static int member_status_available(int status)
3252  return status == AST_DEVICE_NOT_INUSE || status == AST_DEVICE_UNKNOWN;
3253 }
3254 
3255 /*!
3256  * \internal
3257  * \brief Clear the member call pending flag.
3258  *
3259  * \param mem Queue member.
3260  *
3261  * \return Nothing
3262  */
3263 static void member_call_pending_clear(struct member *mem)
3265  ao2_lock(mem);
3266  mem->call_pending = 0;
3267  ao2_unlock(mem);
3268 }
3269 
3270 /*!
3271  * \internal
3272  * \brief Set the member call pending flag.
3273  *
3274  * \param mem Queue member.
3275  *
3276  * \retval non-zero if call pending flag was already set.
3277  */
3278 static int member_call_pending_set(struct member *mem)
3280  int old_pending;
3281 
3282  ao2_lock(mem);
3283  old_pending = mem->call_pending;
3284  mem->call_pending = 1;
3285  ao2_unlock(mem);
3286 
3287  return old_pending;
3288 }
3289 
3290 /*!
3291  * \internal
3292  * \brief Determine if can ring a queue entry.
3293  *
3294  * \param qe Queue entry to check.
3295  * \param call Member call attempt.
3296  *
3297  * \retval non-zero if an entry can be called.
3298  */
3299 static int can_ring_entry(struct queue_ent *qe, struct callattempt *call)
3301  if (call->member->paused) {
3302  if (queue_debug)
3303  ast_log(LOG_NOTICE, "%s paused, can't receive call\n", call->interface);
3304  return 0;
3305  }
3306 
3307  if (!qe->parent->ringinuse && !member_status_available(call->member->status)) {
3308  if (queue_debug)
3309  ast_log(LOG_NOTICE, "%s not available, can't receive call\n", call->interface);
3310  return 0;
3311  }
3312 
3313  if ((call->lastqueue && call->lastqueue->wrapuptime && (time(NULL) - call->lastcall < call->lastqueue->wrapuptime))
3314  || (!call->lastqueue && qe->parent->wrapuptime && (time(NULL) - call->lastcall < qe->parent->wrapuptime))) {
3315  if (queue_debug)
3316  ast_log(LOG_NOTICE, "Wrapuptime not yet expired on queue %s for %s\n",
3317  (call->lastqueue ? call->lastqueue->name : qe->parent->name),
3318  call->interface);
3319  return 0;
3320  }
3321 
3322  if (use_weight && compare_weight(qe->parent, call->member)) {
3323  if (queue_debug)
3324  ast_log(LOG_NOTICE, "Priority queue delaying call to %s:%s\n",
3325  qe->parent->name, call->interface);
3326  return 0;
3327  }
3328 
3329  if (!qe->parent->ringinuse) {
3330  if (member_call_pending_set(call->member)) {
3331  if (queue_debug)
3332  ast_log(LOG_NOTICE, "%s has another call pending, can't receive call\n",
3333  call->interface);
3334  return 0;
3335  }
3336 
3337  /*
3338  * The queue member is available. Get current status to be sure
3339  * because the device state and extension state callbacks may
3340  * not have updated the status yet.
3341  */
3343  ast_debug(1, "%s actually not available, can't receive call\n",
3344  call->interface);
3346  return 0;
3347  }
3348  }
3349 
3350  return 1;
3351 }
3352 
3353 /*!
3354  * \brief Part 2 of ring_one
3355  *
3356  * Does error checking before attempting to request a channel and call a member.
3357  * This function is only called from ring_one().
3358  * Failure can occur if:
3359  * - Agent on call
3360  * - Agent is paused
3361  * - Wrapup time not expired
3362  * - Priority by another queue
3363  *
3364  * \retval 1 on success to reach a free agent
3365  * \retval 0 on failure to get agent.
3366  */
3367 static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
3369  int res;
3370  int status;
3371  char tech[256];
3372  char *location, *location2;
3373  const char *macrocontext, *macroexten;
3374  char pickupmark[256], chan[128];
3375 
3376  /* on entry here, we know that tmp->chan == NULL */
3377  if (!can_ring_entry(qe, tmp)) {
3378  tmp->stillgoing = 0;
3379  (*busies)++;
3380  return 0;
3381  }
3383 
3384  ast_copy_string(tech, tmp->interface, sizeof(tech));
3385  if ((location = strchr(tech, '/')))
3386  *location++ = '\0';
3387  else
3388  location = "";
3389 
3390  /* Request the peer */
3391  tmp->chan = ast_request(tech, qe->chan->nativeformats, qe->chan, location, &status);
3392  if (!tmp->chan) { /* If we can't, just go on to the next call */
3393  if (queue_debug)
3394  ast_log(LOG_NOTICE, "Unable to create channel of type '%s' for Queue\n", tech);
3395  ao2_lock(qe->parent);
3396  qe->parent->rrpos++;
3397  qe->linpos++;
3398  ao2_unlock(qe->parent);
3399 
3401 
3402  if (qe->chan->cdr) {
3403  ast_cdr_busy(qe->chan->cdr);
3404  }
3405  tmp->stillgoing = 0;
3406  (*busies)++;
3407  return 0;
3408  }
3409 
3410  ast_channel_lock_both(tmp->chan, qe->chan);
3411 
3412  if (qe->cancel_answered_elsewhere) {
3414  }
3415  tmp->chan->appl = "AppQueue";
3416  tmp->chan->data = "(Outgoing Line)";
3417  memset(&tmp->chan->whentohangup, 0, sizeof(tmp->chan->whentohangup));
3418 
3419  /* If the new channel has no callerid, try to guess what it should be */
3420  if (!tmp->chan->caller.id.number.valid) {
3421  if (qe->chan->connected.id.number.valid) {
3422  struct ast_party_caller caller;
3423 
3424  ast_party_caller_set_init(&caller, &tmp->chan->caller);
3425  caller.id = qe->chan->connected.id;
3426  caller.ani = qe->chan->connected.ani;
3427  ast_channel_set_caller_event(tmp->chan, &caller, NULL);
3428  } else if (!ast_strlen_zero(qe->chan->dialed.number.str)) {
3429  ast_set_callerid(tmp->chan, qe->chan->dialed.number.str, NULL, NULL);
3430  } else if (!ast_strlen_zero(S_OR(qe->chan->macroexten, qe->chan->exten))) {
3431  ast_set_callerid(tmp->chan, S_OR(qe->chan->macroexten, qe->chan->exten), NULL, NULL);
3432  }
3433  tmp->dial_callerid_absent = 1;
3434  }
3435 
3437 
3439 
3441 
3442  /* Inherit specially named variables from parent channel */
3445 
3446  /* Presense of ADSI CPE on outgoing channel follows ours */
3447  tmp->chan->adsicpe = qe->chan->adsicpe;
3448 
3449  /* Inherit context and extension */
3450  macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT");
3451  ast_string_field_set(tmp->chan, dialcontext, ast_strlen_zero(macrocontext) ? qe->chan->context : macrocontext);
3452  macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN");
3453  if (!ast_strlen_zero(macroexten))
3454  ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten));
3455  else
3456  ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten));
3457  if (ast_cdr_isset_unanswered()) {
3458  /* they want to see the unanswered dial attempts! */
3459  /* set up the CDR fields on all the CDRs to give sensical information */
3460  ast_cdr_setdestchan(tmp->chan->cdr, tmp->chan->name);
3461  strcpy(tmp->chan->cdr->clid, qe->chan->cdr->clid);
3462  strcpy(tmp->chan->cdr->channel, qe->chan->cdr->channel);
3463  strcpy(tmp->chan->cdr->src, qe->chan->cdr->src);
3464  strcpy(tmp->chan->cdr->dst, qe->chan->exten);
3465  strcpy(tmp->chan->cdr->dcontext, qe->chan->context);
3466  strcpy(tmp->chan->cdr->lastapp, qe->chan->cdr->lastapp);
3467  strcpy(tmp->chan->cdr->lastdata, qe->chan->cdr->lastdata);
3468  tmp->chan->cdr->amaflags = qe->chan->cdr->amaflags;
3469  strcpy(tmp->chan->cdr->accountcode, qe->chan->cdr->accountcode);
3470  strcpy(tmp->chan->cdr->userfield, qe->chan->cdr->userfield);
3471  }
3472 
3473  ast_channel_unlock(tmp->chan);
3474  ast_channel_unlock(qe->chan);
3475 
3476  /* Add a PICKUPMARK variable to ringing interface */
3477  if (option_debug > 2)
3478  ast_log(LOG_DEBUG, "chan %s, tech: %s, part %s\n", tmp->chan->name, tech, location);
3479  /* Delete DAHDI ring pattern in tech like DAHDI/1r2 */
3480  ast_copy_string(chan, location, sizeof(chan));
3481  if (!strncasecmp(tech, "dahdi", 5)) {
3482  if((chan[0] > '0') && (chan[0] <= '9')) {
3483  if ((location2 = strchr(chan, 'r')))
3484  *location2++ = '\0';
3485  }
3486  }
3487  snprintf(pickupmark, sizeof(pickupmark), "%s/%s", tech, chan);
3488  pbx_builtin_setvar_helper(tmp->chan, "PICKUPMARK", pickupmark);
3489 
3490  /* Place the call, but don't wait on the answer */
3491  if ((res = ast_call(tmp->chan, location, 0))) {
3492  /* Again, keep going even if there's an error */
3493  ast_verb(3, "Couldn't call %s\n", tmp->interface);
3494  do_hang(tmp);
3496  ++*busies;
3497  return 0;
3498  }
3499 
3500  if (qe->parent->eventwhencalled) {
3501  char vars[2048];
3502 
3503  ast_channel_lock_both(tmp->chan, qe->chan);
3504 
3505  manager_event(EVENT_FLAG_AGENT, "AgentCalled",
3506  "Queue: %s\r\n"
3507  "AgentCalled: %s\r\n"
3508  "AgentName: %s\r\n"
3509  "ChannelCalling: %s\r\n"
3510  "DestinationChannel: %s\r\n"
3511  "CallerIDNum: %s\r\n"
3512  "CallerIDName: %s\r\n"
3513  "ConnectedLineNum: %s\r\n"
3514  "ConnectedLineName: %s\r\n"
3515  "Context: %s\r\n"
3516  "Extension: %s\r\n"
3517  "Priority: %d\r\n"
3518  "Uniqueid: %s\r\n"
3519  "%s",
3520  qe->parent->name, tmp->interface, tmp->member->membername, qe->chan->name, tmp->chan->name,
3521  S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"),
3522  S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"),
3523  S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"),
3524  S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"),
3525  qe->chan->context, qe->chan->exten, qe->chan->priority, qe->chan->uniqueid,
3526  qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
3527 
3528  ast_channel_unlock(tmp->chan);
3529  ast_channel_unlock(qe->chan);
3530 
3531  ast_verb(3, "Called %s\n", tmp->interface);
3532  }
3533 
3535  return 1;
3536 }
3537 
3538 /*! \brief find the entry with the best metric, or NULL */
3539 static struct callattempt *find_best(struct callattempt *outgoing)
3541  struct callattempt *best = NULL, *cur;
3542 
3543  for (cur = outgoing; cur; cur = cur->q_next) {
3544  if (cur->stillgoing && /* Not already done */
3545  !cur->chan && /* Isn't already going */
3546  (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */
3547  best = cur;
3548  }
3549  }
3550 
3551  return best;
3552 }
3553 
3554 /*!
3555  * \brief Place a call to a queue member.
3556  *
3557  * Once metrics have been calculated for each member, this function is used
3558  * to place a call to the appropriate member (or members). The low-level
3559  * channel-handling and error detection is handled in ring_entry
3560  *
3561  * \retval 1 if a member was called successfully
3562  * \retval 0 otherwise
3563  */
3564 static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
3566  int ret = 0;
3567 
3568  while (ret == 0) {
3569  struct callattempt *best = find_best(outgoing);
3570  if (!best) {
3571  ast_debug(1, "Nobody left to try ringing in queue\n");
3572  break;
3573  }
3574  if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
3575  struct callattempt *cur;
3576  /* Ring everyone who shares this best metric (for ringall) */
3577  for (cur = outgoing; cur; cur = cur->q_next) {
3578  if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
3579  ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
3580  ret |= ring_entry(qe, cur, busies);
3581  }
3582  }
3583  } else {
3584  /* Ring just the best channel */
3585  ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric);
3586  ret = ring_entry(qe, best, busies);
3587  }
3588 
3589  /* If we have timed out, break out */
3590  if (qe->expire && (time(NULL) >= qe->expire)) {
3591  ast_debug(1, "Queue timed out while ringing members.\n");
3592  ret = 0;
3593  break;
3594  }
3595  }
3596 
3597  return ret;
3598 }
3599 
3600 /*! \brief Search for best metric and add to Round Robbin queue */
3601 static int store_next_rr(struct queue_ent *qe, struct callattempt *outgoing)
3603  struct callattempt *best = find_best(outgoing);
3604 
3605  if (best) {
3606  /* Ring just the best channel */
3607  ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
3608  qe->parent->rrpos = best->metric % 1000;
3609  } else {
3610  /* Just increment rrpos */
3611  if (qe->parent->wrapped) {
3612  /* No more channels, start over */
3613  qe->parent->rrpos = 0;
3614  } else {
3615  /* Prioritize next entry */
3616  qe->parent->rrpos++;
3617  }
3618  }
3619  qe->parent->wrapped = 0;
3620 
3621  return 0;
3622 }
3623 
3624 /*! \brief Search for best metric and add to Linear queue */
3625 static int store_next_lin(struct queue_ent *qe, struct callattempt *outgoing)
3627  struct callattempt *best = find_best(outgoing);
3628 
3629  if (best) {
3630  /* Ring just the best channel */
3631  ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
3632  qe->linpos = best->metric % 1000;
3633  } else {
3634  /* Just increment rrpos */
3635  if (qe->linwrapped) {
3636  /* No more channels, start over */
3637  qe->linpos = 0;
3638  } else {
3639  /* Prioritize next entry */
3640  qe->linpos++;
3641  }
3642  }
3643  qe->linwrapped = 0;
3644 
3645  return 0;
3646 }
3647 
3648 /*! \brief Playback announcement to queued members if period has elapsed */
3649 static int say_periodic_announcement(struct queue_ent *qe, int ringing)
3651  int res = 0;
3652  time_t now;
3653 
3654  /* Get the current time */
3655  time(&now);
3656 
3657  /* Check to see if it is time to announce */
3659  return 0;
3660 
3661  /* Stop the music on hold so we can play our own file */
3662  if (ringing)
3663  ast_indicate(qe->chan,-1);
3664  else
3665  ast_moh_stop(qe->chan);
3666 
3667  ast_verb(3, "Playing periodic announcement\n");
3668 
3670  qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce;
3671  } else if (qe->last_periodic_announce_sound >= qe->parent->numperiodicannounce ||
3674  }
3675 
3676  /* play the announcement */
3678 
3679  if (res > 0 && !valid_exit(qe, res))
3680  res = 0;
3681 
3682  /* Resume Music on Hold if the caller is going to stay in the queue */
3683  if (!res) {
3684  if (ringing)
3686  else
3687  ast_moh_start(qe->chan, qe->moh, NULL);
3688  }
3689 
3690  /* update last_periodic_announce_time */
3692  time(&qe->last_periodic_announce_time);
3693  else
3694  qe->last_periodic_announce_time = now;
3695 
3696  /* Update the current periodic announcement to the next announcement */
3697  if (!qe->parent->randomperiodicannounce) {
3699  }
3700 
3701  return res;
3702 }
3703 
3704 /*! \brief Record that a caller gave up on waiting in queue */
3705 static void record_abandoned(struct queue_ent *qe)
3707  set_queue_variables(qe->parent, qe->chan);
3708  ao2_lock(qe->parent);
3709  manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
3710  "Queue: %s\r\n"
3711  "Uniqueid: %s\r\n"
3712  "Position: %d\r\n"
3713  "OriginalPosition: %d\r\n"
3714  "HoldTime: %d\r\n",
3715  qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start));
3716 
3717  qe->parent->callsabandoned++;
3718  ao2_unlock(qe->parent);
3719 }
3720 
3721 /*! \brief RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. */
3722 static void rna(int rnatime, struct queue_ent *qe, char *interface, char *membername, int pause)
3724  ast_verb(3, "Nobody picked up in %d ms\n", rnatime);
3725 
3726  /* Stop ringing, and resume MOH if specified */
3727  if (qe->ring_when_ringing) {
3728  ast_indicate(qe->chan, -1);
3729  ast_moh_start(qe->chan, qe->moh, NULL);
3730  }
3731 
3732  if (qe->parent->eventwhencalled) {
3733  char vars[2048];
3734 
3735  manager_event(EVENT_FLAG_AGENT, "AgentRingNoAnswer",
3736  "Queue: %s\r\n"
3737  "Uniqueid: %s\r\n"
3738  "Channel: %s\r\n"
3739  "Member: %s\r\n"
3740  "MemberName: %s\r\n"
3741  "Ringtime: %d\r\n"
3742  "%s",
3743  qe->parent->name,
3744  qe->chan->uniqueid,
3745  qe->chan->name,
3746  interface,
3747  membername,
3748  rnatime,
3749  qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
3750  }
3751  ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
3752  if (qe->parent->autopause != QUEUE_AUTOPAUSE_OFF && pause) {
3753  if (qe->parent->autopause == QUEUE_AUTOPAUSE_ON) {
3754  if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) {
3755  ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n",
3756  interface, qe->parent->name);
3757  } else {
3758  ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
3759  }
3760  } else {
3761  /* If queue autopause is mode all, just don't send any queue to stop.
3762  * the function will stop in all queues */
3763  if (!set_member_paused("", interface, "Auto-Pause", 1)) {
3764  ast_verb(3, "Auto-Pausing Queue Member %s in all queues since they failed to answer on queue %s.\n",
3765  interface, qe->parent->name);
3766  } else {
3767  ast_verb(3, "Failed to pause Queue Member %s in all queues!\n", interface);
3768  }
3769  }
3770  }
3771  return;
3772 }
3773 
3774 #define AST_MAX_WATCHERS 256
3775 /*!
3776  * \brief Wait for a member to answer the call
3777  *
3778  * \param[in] qe the queue_ent corresponding to the caller in the queue
3779  * \param[in] outgoing the list of callattempts. Relevant ones will have their chan and stillgoing parameters non-zero
3780  * \param[in] to the amount of time (in milliseconds) to wait for a response
3781  * \param[out] digit if a user presses a digit to exit the queue, this is the digit the caller pressed
3782  * \param[in] prebusies number of busy members calculated prior to calling wait_for_answer
3783  * \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
3784  * \param[in] forwardsallowed used to detect if we should allow call forwarding, based on the 'i' option to Queue()
3785  *
3786  * \todo eventually all call forward logic should be intergerated into and replaced by ast_call_forward()
3787  */
3788 static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed, int ringing)
3790  const char *queue = qe->parent->name;
3791  struct callattempt *o, *start = NULL, *prev = NULL;
3792  int status;
3793  int numbusies = prebusies;
3794  int numnochan = 0;
3795  int stillgoing = 0;
3796  int orig = *to;
3797  struct ast_frame *f;
3798  struct callattempt *peer = NULL;
3799  struct ast_channel *winner;
3800  struct ast_channel *in = qe->chan;
3801  char on[80] = "";
3802  char membername[80] = "";
3803  long starttime = 0;
3804  long endtime = 0;
3805 #ifdef HAVE_EPOLL
3806  struct callattempt *epollo;
3807 #endif
3808  struct ast_party_connected_line connected_caller;
3809  char *inchan_name;
3810  struct timeval start_time_tv = ast_tvnow();
3811 
3812  ast_party_connected_line_init(&connected_caller);
3813 
3814  ast_channel_lock(qe->chan);
3815  inchan_name = ast_strdupa(qe->chan->name);
3816  ast_channel_unlock(qe->chan);
3817 
3818  starttime = (long) time(NULL);
3819 #ifdef HAVE_EPOLL
3820  for (epollo = outgoing; epollo; epollo = epollo->q_next) {
3821  if (epollo->chan)
3822  ast_poll_channel_add(in, epollo->chan);
3823  }
3824 #endif
3825 
3826  while ((*to = ast_remaining_ms(start_time_tv, orig)) && !peer) {
3827  int numlines, retry, pos = 1;
3828  struct ast_channel *watchers[AST_MAX_WATCHERS];
3829  watchers[0] = in;
3830  start = NULL;
3831 
3832  for (retry = 0; retry < 2; retry++) {
3833  numlines = 0;
3834  for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
3835  if (o->stillgoing) { /* Keep track of important channels */
3836  stillgoing = 1;
3837  if (o->chan) {
3838  if (pos < AST_MAX_WATCHERS) {
3839  watchers[pos++] = o->chan;
3840  }
3841  if (!start)
3842  start = o;
3843  else
3844  prev->call_next = o;
3845  prev = o;
3846  }
3847  }
3848  numlines++;
3849  }
3850  if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
3851  (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */)
3852  break;
3853  /* On "ringall" strategy we only move to the next penalty level
3854  when *all* ringing phones are done in the current penalty level */
3855  ring_one(qe, outgoing, &numbusies);
3856  /* and retry... */
3857  }
3858  if (pos == 1 /* not found */) {
3859  if (numlines == (numbusies + numnochan)) {
3860  ast_debug(1, "Everyone is busy at this time\n");
3861  //if (in->cdr && in->_state != AST_STATE_UP) {
3862  // ast_cdr_busy(in->cdr);
3863  //}
3864  } else {
3865  ast_debug(3, "No one is answering queue '%s' (%d numlines / %d busies / %d failed channels)\n", queue, numlines, numbusies, numnochan);
3866  if (in->cdr && in->_state != AST_STATE_UP) {
3867  ast_cdr_failed(in->cdr);
3868  }
3869  }
3870  *to = 0;
3871  return NULL;
3872  }
3873 
3874  /* Poll for events from both the incoming channel as well as any outgoing channels */
3875  winner = ast_waitfor_n(watchers, pos, to);
3876 
3877  /* Service all of the outgoing channels */
3878  for (o = start; o; o = o->call_next) {
3879  /* We go with a fixed buffer here instead of using ast_strdupa. Using
3880  * ast_strdupa in a loop like this one can cause a stack overflow
3881  */
3882  char ochan_name[AST_CHANNEL_NAME];
3883 
3884  if (o->chan) {
3885  ast_channel_lock(o->chan);
3886  ast_copy_string(ochan_name, o->chan->name, sizeof(ochan_name));
3888  }
3889  if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
3890  if (!peer) {
3891  ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
3892  if (!o->block_connected_update) {
3893  if (o->pending_connected_update) {
3894  if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
3896  }
3897  } else if (!o->dial_callerid_absent) {
3898  ast_channel_lock(o->chan);
3899  ast_connected_line_copy_from_caller(&connected_caller, &o->chan->caller);
3902  if (ast_channel_connected_line_macro(o->chan, in, &connected_caller, 1, 0)) {
3903  ast_channel_update_connected_line(in, &connected_caller, NULL);
3904  }
3905  ast_party_connected_line_free(&connected_caller);
3906  }
3907  }
3908  if (o->aoc_s_rate_list) {
3909  size_t encoded_size;
3910  struct ast_aoc_encoded *encoded;
3911  if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
3912  ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
3913  ast_aoc_destroy_encoded(encoded);
3914  }
3915  }
3916  peer = o;
3917  }
3918  } else if (o->chan && (o->chan == winner)) {
3919 
3920  ast_copy_string(on, o->member->interface, sizeof(on));
3921  ast_copy_string(membername, o->member->membername, sizeof(membername));
3922 
3923  /* Before processing channel, go ahead and check for forwarding */
3924  if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) {
3925  ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, o->chan->call_forward);
3926  numnochan++;
3927  do_hang(o);
3928  winner = NULL;
3929  continue;
3930  } else if (!ast_strlen_zero(o->chan->call_forward)) {
3931  struct ast_channel *original = o->chan;
3932  char tmpchan[256];
3933  char *stuff;
3934  char *tech;
3935 
3936  ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
3937  if ((stuff = strchr(tmpchan, '/'))) {
3938  *stuff++ = '\0';
3939  tech = tmpchan;
3940  } else {
3941  snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
3942  stuff = tmpchan;
3943  tech = "Local";
3944  }
3945  if (!strcasecmp(tech, "Local")) {
3946  /*
3947  * Drop the connected line update block for local channels since
3948  * this is going to run dialplan and the user can change his
3949  * mind about what connected line information he wants to send.
3950  */
3951  o->block_connected_update = 0;
3952  }
3953 
3954  ast_cel_report_event(in, AST_CEL_FORWARD, NULL, o->chan->call_forward, NULL);
3955 
3956  ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name);
3957  /* Setup parameters */
3958  o->chan = ast_request(tech, in->nativeformats, in, stuff, &status);
3959  if (!o->chan) {
3961  "Forwarding failed to create channel to dial '%s/%s'\n",
3962  tech, stuff);
3963  o->stillgoing = 0;
3964  numnochan++;
3965  } else {
3966  ast_channel_lock_both(o->chan, original);
3969  ast_channel_unlock(original);
3970 
3971  ast_channel_lock_both(o->chan, in);
3974 
3975  if (o->pending_connected_update) {
3976  /*
3977  * Re-seed the callattempt's connected line information with
3978  * previously acquired connected line info from the queued
3979  * channel. The previously acquired connected line info could
3980  * have been set through the CONNECTED_LINE dialplan function.
3981  */
3982  o->pending_connected_update = 0;
3984  }
3985 
3987 
3988  if (!o->chan->redirecting.from.number.valid
3990  /*
3991  * The call was not previously redirected so it is
3992  * now redirected from this number.
3993  */
3996  o->chan->redirecting.from.number.valid = 1;
3998  ast_strdup(S_OR(in->macroexten, in->exten));
3999  }
4000 
4002 
4006 
4007  ast_channel_unlock(in);
4009  && !o->block_connected_update) {
4010  struct ast_party_redirecting redirecting;
4011 
4012  /*
4013  * Redirecting updates to the caller make sense only on single
4014  * call at a time strategies.
4015  *
4016  * We must unlock o->chan before calling
4017  * ast_channel_redirecting_macro, because we put o->chan into
4018  * autoservice there. That is pretty much a guaranteed
4019  * deadlock. This is why the handling of o->chan's lock may
4020  * seem a bit unusual here.
4021  */
4022  ast_party_redirecting_init(&redirecting);
4023  ast_party_redirecting_copy(&redirecting, &o->chan->redirecting);
4025  if (ast_channel_redirecting_macro(o->chan, in, &redirecting, 1, 0)) {
4026  ast_channel_update_redirecting(in, &redirecting, NULL);
4027  }
4028  ast_party_redirecting_free(&redirecting);
4029  } else {
4031  }
4032 
4033  if (ast_call(o->chan, stuff, 0)) {
4034  ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n",
4035  tech, stuff);
4036  do_hang(o);
4037  numnochan++;
4038  }
4039  }
4040  /* Hangup the original channel now, in case we needed it */
4041  ast_hangup(winner);
4042  continue;
4043  }
4044  f = ast_read(winner);
4045  if (f) {
4046  if (f->frametype == AST_FRAME_CONTROL) {
4047  switch (f->subclass.integer) {
4048  case AST_CONTROL_ANSWER:
4049  /* This is our guy if someone answered. */
4050  if (!peer) {
4051  ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
4052  if (!o->block_connected_update) {
4053  if (o->pending_connected_update) {
4054  if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
4056  }
4057  } else if (!o->dial_callerid_absent) {
4058  ast_channel_lock(o->chan);
4059  ast_connected_line_copy_from_caller(&connected_caller, &o->chan->caller);
4062  if (ast_channel_connected_line_macro(o->chan, in, &connected_caller, 1, 0)) {
4063  ast_channel_update_connected_line(in, &connected_caller, NULL);
4064  }
4065  ast_party_connected_line_free(&connected_caller);
4066  }
4067  }
4068  if (o->aoc_s_rate_list) {
4069  size_t encoded_size;
4070  struct ast_aoc_encoded *encoded;
4071  if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
4072  ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
4073  ast_aoc_destroy_encoded(encoded);
4074  }
4075  }
4076  peer = o;
4077  }
4078  break;
4079  case AST_CONTROL_BUSY:
4080  ast_verb(3, "%s is busy\n", ochan_name);
4081  //if (in->cdr)
4082  // ast_cdr_busy(in->cdr);
4083  do_hang(o);
4084  endtime = (long) time(NULL);
4085  endtime -= starttime;
4086  rna(endtime * 1000, qe, on, membername, 0);
4087  if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
4088  if (qe->parent->timeoutrestart) {
4089  start_time_tv = ast_tvnow();
4090  }
4091  /* Have enough time for a queue member to answer? */
4092  if (ast_remaining_ms(start_time_tv, orig) > 500) {
4093  ring_one(qe, outgoing, &numbusies);
4094  starttime = (long) time(NULL);
4095  }
4096  }
4097  numbusies++;
4098  break;
4100  ast_verb(3, "%s is circuit-busy\n", ochan_name);
4101  if (in->cdr)
4102  ast_cdr_failed(in->cdr);
4103  endtime = (long) time(NULL);
4104  endtime -= starttime;
4105  rna(endtime * 1000, qe, on, membername, 0);
4106  do_hang(o);
4107  if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
4108  if (qe->parent->timeoutrestart) {
4109  start_time_tv = ast_tvnow();
4110  }
4111  if (ast_remaining_ms(start_time_tv, orig) > 500) {
4112  ring_one(qe, outgoing, &numbusies);
4113  starttime = (long) time(NULL);
4114  }
4115  }
4116  numbusies++;
4117  break;
4118  case AST_CONTROL_RINGING:
4119  ast_verb(3, "%s is ringing\n", ochan_name);
4120 
4121  /* Start ring indication when the channel is ringing, if specified */
4122  if (qe->ring_when_ringing) {
4123  ast_moh_stop(qe->chan);
4125  }
4126  break;
4127  case AST_CONTROL_OFFHOOK:
4128  /* Ignore going off hook */
4129  break;
4131  if (o->block_connected_update) {
4132  ast_verb(3, "Connected line update to %s prevented.\n", inchan_name);
4133  break;
4134  }
4135  if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
4136  struct ast_party_connected_line connected;
4137 
4138  ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ochan_name, inchan_name);
4140  ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected);
4141  ast_party_connected_line_set(&o->connected, &connected, NULL);
4142  ast_party_connected_line_free(&connected);
4143  o->pending_connected_update = 1;
4144  break;
4145  }
4146 
4147  /*
4148  * Prevent using the CallerID from the outgoing channel since we
4149  * got a connected line update from it.
4150  */
4151  o->dial_callerid_absent = 1;
4152 
4153  if (ast_channel_connected_line_macro(o->chan, in, f, 1, 1)) {
4155  }
4156  break;
4157  case AST_CONTROL_AOC:
4158  {
4159  struct ast_aoc_decoded *decoded = ast_aoc_decode(f->data.ptr, f->datalen, o->chan);
4160  if (decoded && (ast_aoc_get_msg_type(decoded) == AST_AOC_S)) {
4162  o->aoc_s_rate_list = decoded;
4163  } else {
4164  ast_aoc_destroy_decoded(decoded);
4165  }
4166  }
4167  break;
4169  if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
4170  /*
4171  * Redirecting updates to the caller make sense only on single
4172  * call at a time strategies.
4173  */
4174  break;
4175  }
4176  if (o->block_connected_update) {
4177  ast_verb(3, "Redirecting update to %s prevented\n",
4178  inchan_name);
4179  break;
4180  }
4181  ast_verb(3, "%s redirecting info has changed, passing it to %s\n",
4182  ochan_name, inchan_name);
4183  if (ast_channel_redirecting_macro(o->chan, in, f, 1, 1)) {
4185  }
4186  break;
4187  default:
4188  ast_debug(1, "Dunno what to do with control type %d\n", f->subclass.integer);
4189  break;
4190  }
4191  }
4192  ast_frfree(f);
4193  } else { /* ast_read() returned NULL */
4194  endtime = (long) time(NULL) - starttime;
4195  rna(endtime * 1000, qe, on, membername, 1);
4196  do_hang(o);
4197  if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
4198  if (qe->parent->timeoutrestart) {
4199  start_time_tv = ast_tvnow();
4200  }
4201  if (ast_remaining_ms(start_time_tv, orig) > 500) {
4202  ring_one(qe, outgoing, &numbusies);
4203  starttime = (long) time(NULL);
4204  }
4205  }
4206  }
4207  }
4208  }
4209 
4210  /* If we received an event from the caller, deal with it. */
4211  if (winner == in) {
4212  f = ast_read(in);
4213  if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) {
4214  /* Got hung up */
4215  *to = -1;
4216  if (f) {
4217  if (f->data.uint32) {
4218  in->hangupcause = f->data.uint32;
4219  }
4220  ast_frfree(f);
4221  }
4222  return NULL;
4223  }
4224 
4225  if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) {
4226  ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
4227  *to = 0;
4228  ast_frfree(f);
4229  if (in->cdr && in->_state != AST_STATE_UP) {
4230  ast_cdr_noanswer(in->cdr);
4231  }
4232  return NULL;
4233  }
4234  if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass.integer)) {
4235  ast_verb(3, "User pressed digit: %c\n", f->subclass.integer);
4236  *to = 0;
4237  *digit = f->subclass.integer;
4238  ast_frfree(f);
4239  if (in->cdr && in->_state != AST_STATE_UP) {
4240  ast_cdr_noanswer(in->cdr);
4241  }
4242  return NULL;
4243  }
4244 
4245  /* Send the frame from the in channel to all outgoing channels. */
4246  for (o = start; o; o = o->call_next) {
4247  if (!o->stillgoing || !o->chan) {
4248  /* This outgoing channel has died so don't send the frame to it. */
4249  continue;
4250  }
4251  switch (f->frametype) {
4252  case AST_FRAME_CONTROL:
4253  switch (f->subclass.integer) {
4255  if (ast_channel_connected_line_macro(in, o->chan, f, 0, 1)) {
4257  }
4258  break;
4260  if (ast_channel_redirecting_macro(in, o->chan, f, 0, 1)) {
4262  }
4263  break;
4264  default:
4265  /* We are not going to do anything with this frame. */
4266  goto skip_frame;
4267  }
4268  break;
4269  default:
4270  /* We are not going to do anything with this frame. */
4271  goto skip_frame;
4272  }
4273  }
4274 skip_frame:;
4275 
4276  ast_frfree(f);
4277  }
4278  }
4279 
4280  /* Make a position announcement, if enabled */
4282  say_position(qe, ringing);
4283  }
4284 
4285  /* Make a periodic announcement, if enabled */
4287  say_periodic_announcement(qe, ringing);
4288  }
4289 
4290  if (!*to) {
4291  for (o = start; o; o = o->call_next) {
4292  rna(orig, qe, o->interface, o->member->membername, 1);
4293  }
4294  }
4295 
4296  if (in->cdr
4297  && in->_state != AST_STATE_UP
4298  && (!*to || ast_check_hangup(in))) {
4299  ast_cdr_noanswer(in->cdr);
4300  }
4301 
4302 #ifdef HAVE_EPOLL
4303  for (epollo = outgoing; epollo; epollo = epollo->q_next) {
4304  if (epollo->chan)
4305  ast_poll_channel_del(in, epollo->chan);
4306  }
4307 #endif
4308 
4309  return peer;
4310 }
4311 
4312 /*!
4313  * \brief Check if we should start attempting to call queue members.
4314  *
4315  * A simple process, really. Count the number of members who are available
4316  * to take our call and then see if we are in a position in the queue at
4317  * which a member could accept our call.
4318  *
4319  * \param[in] qe The caller who wants to know if it is his turn
4320  * \retval 0 It is not our turn
4321  * \retval 1 It is our turn
4322  */
4323 static int is_our_turn(struct queue_ent *qe)
4325  struct queue_ent *ch;
4326  int res;
4327  int avl;
4328  int idx = 0;
4329  /* This needs a lock. How many members are available to be served? */
4330  ao2_lock(qe->parent);
4331 
4332  avl = num_available_members(qe->parent);
4333 
4334  ch = qe->parent->head;
4335 
4336  ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member");
4337 
4338  while ((idx < avl) && (ch) && (ch != qe)) {
4339  if (!ch->pending)
4340  idx++;
4341  ch = ch->next;
4342  }
4343 
4344  ao2_unlock(qe->parent);
4345  /* If the queue entry is within avl [the number of available members] calls from the top ...
4346  * Autofill and position check added to support autofill=no (as only calls
4347  * from the front of the queue are valid when autofill is disabled)
4348  */
4349  if (ch && idx < avl && (qe->parent->autofill || qe->pos == 1)) {
4350  ast_debug(1, "It's our turn (%s).\n", qe->chan->name);
4351  res = 1;
4352  } else {
4353  ast_debug(1, "It's not our turn (%s).\n", qe->chan->name);
4354  res = 0;
4355  }
4356 
4357  return res;
4358 }
4359 
4360 /*!
4361  * \brief update rules for queues
4362  *
4363  * Calculate min/max penalties making sure if relative they stay within bounds.
4364  * Update queues penalty and set dialplan vars, goto next list entry.
4365 */
4366 static void update_qe_rule(struct queue_ent *qe)
4368  int max_penalty = INT_MAX;
4369 
4370  if (qe->max_penalty != INT_MAX) {
4371  char max_penalty_str[20];
4372 
4373  if (qe->pr->max_relative) {
4374  max_penalty = qe->max_penalty + qe->pr->max_value;
4375  } else {
4376  max_penalty = qe->pr->max_value;
4377  }
4378 
4379  /* a relative change to the penalty could put it below 0 */
4380  if (max_penalty < 0) {
4381  max_penalty = 0;
4382  }
4383 
4384  snprintf(max_penalty_str, sizeof(max_penalty_str), "%d", max_penalty);
4385  pbx_builtin_setvar_helper(qe->chan, "QUEUE_MAX_PENALTY", max_penalty_str);
4386  qe->max_penalty = max_penalty;
4387  ast_debug(3, "Setting max penalty to %d for caller %s since %d seconds have elapsed\n",
4388  qe->max_penalty, qe->chan->name, qe->pr->time);
4389  }
4390 
4391  if (qe->min_penalty != INT_MAX) {
4392  char min_penalty_str[20];
4393  int min_penalty;
4394 
4395  if (qe->pr->min_relative) {
4396  min_penalty = qe->min_penalty + qe->pr->min_value;
4397  } else {
4398  min_penalty = qe->pr->min_value;
4399  }
4400 
4401  if (min_penalty < 0) {
4402  min_penalty = 0;
4403  }
4404 
4405  if (max_penalty != INT_MAX && min_penalty > max_penalty) {
4406  min_penalty = max_penalty;
4407  }
4408 
4409  snprintf(min_penalty_str, sizeof(min_penalty_str), "%d", min_penalty);
4410  pbx_builtin_setvar_helper(qe->chan, "QUEUE_MIN_PENALTY", min_penalty_str);
4411  qe->min_penalty = min_penalty;
4412  ast_debug(3, "Setting min penalty to %d for caller %s since %d seconds have elapsed\n",
4413  qe->min_penalty, qe->chan->name, qe->pr->time);
4414  }
4415 
4416  qe->pr = AST_LIST_NEXT(qe->pr, list);
4417 }
4418 
4419 /*! \brief The waiting areas for callers who are not actively calling members
4420  *
4421  * This function is one large loop. This function will return if a caller
4422  * either exits the queue or it becomes that caller's turn to attempt calling
4423  * queue members. Inside the loop, we service the caller with periodic announcements,
4424  * holdtime announcements, etc. as configured in queues.conf
4425  *
4426  * \retval 0 if the caller's turn has arrived
4427  * \retval -1 if the caller should exit the queue.
4428  */
4429 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
4431  int res = 0;
4432 
4433  /* This is the holding pen for callers 2 through maxlen */
4434  for (;;) {
4435 
4436  if (is_our_turn(qe))
4437  break;
4438 
4439  /* If we have timed out, break out */
4440  if (qe->expire && (time(NULL) >= qe->expire)) {
4441  *reason = QUEUE_TIMEOUT;
4442  break;
4443  }
4444 
4445  if (qe->parent->leavewhenempty) {
4446  int status = 0;
4447 
4448  if ((status = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty, qe->parent->leavewhenempty, 0))) {
4449  *reason = QUEUE_LEAVEEMPTY;
4450  ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
4451  leave_queue(qe);
4452  break;
4453  }
4454  }
4455 
4456  /* Make a position announcement, if enabled */
4457  if (qe->parent->announcefrequency &&
4458  (res = say_position(qe,ringing)))
4459  break;
4460 
4461  /* If we have timed out, break out */
4462  if (qe->expire && (time(NULL) >= qe->expire)) {
4463  *reason = QUEUE_TIMEOUT;
4464  break;
4465  }
4466 
4467  /* Make a periodic announcement, if enabled */
4468  if (qe->parent->periodicannouncefrequency &&
4469  (res = say_periodic_announcement(qe,ringing)))
4470  break;
4471 
4472  /* see if we need to move to the next penalty level for this queue */
4473  while (qe->pr && ((time(NULL) - qe->start) >= qe->pr->time)) {
4474  update_qe_rule(qe);
4475  }
4476 
4477  /* If we have timed out, break out */
4478  if (qe->expire && (time(NULL) >= qe->expire)) {
4479  *reason = QUEUE_TIMEOUT;
4480  break;
4481  }
4482 
4483  /* Wait a second before checking again */
4484  if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
4485  if (res > 0 && !valid_exit(qe, res))
4486  res = 0;
4487  else
4488  break;
4489  }
4490 
4491  /* If we have timed out, break out */
4492  if (qe->expire && (time(NULL) >= qe->expire)) {
4493  *reason = QUEUE_TIMEOUT;
4494  break;
4495  }
4496  }
4497 
4498  return res;
4499 }
4500 
4501 /*!
4502  * \brief update the queue status
4503  * \retval Always 0
4504 */
4505 static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, int newtalktime)
4507  int oldtalktime;
4508 
4509  struct member *mem;
4510  struct call_queue *qtmp;
4511  struct ao2_iterator queue_iter;
4512 
4513  if (shared_lastcall) {
4514  queue_iter = ao2_iterator_init(queues, 0);
4515  while ((qtmp = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
4516  ao2_lock(qtmp);
4517  if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) {
4518  time(&mem->lastcall);
4519  mem->calls++;
4520  mem->lastqueue = q;
4521  ao2_ref(mem, -1);
4522  }
4523  ao2_unlock(qtmp);
4524  queue_t_unref(qtmp, "Done with iterator");
4525  }
4526  ao2_iterator_destroy(&queue_iter);
4527  } else {
4528  ao2_lock(q);
4529  time(&member->lastcall);
4530  member->calls++;
4531  member->lastqueue = q;
4532  ao2_unlock(q);
4533  }
4534  ao2_lock(q);
4535  q->callscompleted++;
4536  if (callcompletedinsl)
4537  q->callscompletedinsl++;
4538  /* Calculate talktime using the same exponential average as holdtime code*/
4539  oldtalktime = q->talktime;
4540  q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
4541  ao2_unlock(q);
4542  return 0;
4543 }
4544 
4545 /*! \brief Calculate the metric of each member in the outgoing callattempts
4546  *
4547  * A numeric metric is given to each member depending on the ring strategy used
4548  * by the queue. Members with lower metrics will be called before members with
4549  * higher metrics
4550  * \retval -1 if penalties are exceeded
4551  * \retval 0 otherwise
4552  */
4553 static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
4555  /* disregarding penalty on too few members? */
4556  int membercount = ao2_container_count(q->members);
4557  unsigned char usepenalty = (membercount <= q->penaltymemberslimit) ? 0 : 1;
4558 
4559  if (usepenalty) {
4560  if ((qe->max_penalty != INT_MAX && mem->penalty > qe->max_penalty) ||
4561  (qe->min_penalty != INT_MAX && mem->penalty < qe->min_penalty)) {
4562  return -1;
4563  }
4564  } else {
4565  ast_debug(1, "Disregarding penalty, %d members and %d in penaltymemberslimit.\n",
4566  membercount, q->penaltymemberslimit);
4567  }
4568 
4569  switch (q->strategy) {
4571  /* Everyone equal, except for penalty */
4572  tmp->metric = mem->penalty * 1000000 * usepenalty;
4573  break;
4574  case QUEUE_STRATEGY_LINEAR:
4575  if (pos < qe->linpos) {
4576  tmp->metric = 1000 + pos;
4577  } else {
4578  if (pos > qe->linpos)
4579  /* Indicate there is another priority */
4580  qe->linwrapped = 1;
4581  tmp->metric = pos;
4582  }
4583  tmp->metric += mem->penalty * 1000000 * usepenalty;
4584  break;
4587  pos = mem->queuepos;
4588  if (pos < q->rrpos) {
4589  tmp->metric = 1000 + pos;
4590  } else {
4591  if (pos > q->rrpos)
4592  /* Indicate there is another priority */
4593  q->wrapped = 1;
4594  tmp->metric = pos;
4595  }
4596  tmp->metric += mem->penalty * 1000000 * usepenalty;
4597  break;
4598  case QUEUE_STRATEGY_RANDOM:
4599  tmp->metric = ast_random() % 1000;
4600  tmp->metric += mem->penalty * 1000000 * usepenalty;
4601  break;
4603  tmp->metric = ast_random() % ((1 + mem->penalty) * 1000);
4604  break;
4606  tmp->metric = mem->calls;
4607  tmp->metric += mem->penalty * 1000000 * usepenalty;
4608  break;
4610  if (!mem->lastcall)
4611  tmp->metric = 0;
4612  else
4613  tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
4614  tmp->metric += mem->penalty * 1000000 * usepenalty;
4615  break;
4616  default:
4617  ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
4618  break;
4619  }
4620  if (q->ringlimit && (mem->ringcount >= q->ringlimit)) {
4621  tmp->metric += (mem->ringcount / q->ringlimit) * 10000000;
4622  }
4623  if (option_debug)
4624  ast_log(LOG_DEBUG, "New metric %d for member %s with %d rings (limit %d)\n",
4625  tmp->metric, mem->interface, mem->ringcount, q->ringlimit);
4626  return 0;
4627 }
4628 
4629 enum agent_complete_reason {
4633 };
4634 
4635 /*! \brief Send out AMI message with member call completion status information */
4636 static void send_agent_complete(const struct queue_ent *qe, const char *queuename,
4637  const struct ast_channel *peer, const struct member *member, time_t callstart,
4638  char *vars, size_t vars_len, enum agent_complete_reason rsn)
4639 {
4640  const char *reason = NULL; /* silence dumb compilers */
4641 
4642  if (!qe->parent->eventwhencalled)
4643  return;
4644 
4645  switch (rsn) {
4646  case CALLER:
4647  reason = "caller";
4648  break;
4649  case AGENT:
4650  reason = "agent";
4651  break;
4652  case TRANSFER:
4653  reason = "transfer";
4654  break;
4655  }
4656 
4657  manager_event(EVENT_FLAG_AGENT, "AgentComplete",
4658  "Queue: %s\r\n"
4659  "Uniqueid: %s\r\n"
4660  "Channel: %s\r\n"
4661  "Member: %s\r\n"
4662  "MemberName: %s\r\n"
4663  "HoldTime: %ld\r\n"
4664  "TalkTime: %ld\r\n"
4665  "Reason: %s\r\n"
4666  "%s",
4667  queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
4668  (long)(callstart - qe->start), (long)(time(NULL) - callstart), reason,
4669  qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : "");
4670 }
4671 
4672 struct queue_transfer_ds {
4673  struct queue_ent *qe;
4674  struct member *member;
4675  time_t starttime;
4676  int callcompletedinsl;
4677 };
4678 
4679 static void queue_transfer_destroy(void *data)
4681  struct queue_transfer_ds *qtds = data;
4682  ast_free(qtds);
4683 }
4684 
4685 /*! \brief a datastore used to help correctly log attended transfers of queue callers
4686  */
4687 static const struct ast_datastore_info queue_transfer_info = {
4688  .type = "queue_transfer",
4689  .chan_fixup = queue_transfer_fixup,
4690  .destroy = queue_transfer_destroy,
4691 };
4692 
4693 /*! \brief Log an attended transfer when a queue caller channel is masqueraded
4694  *
4695  * When a caller is masqueraded, we want to log a transfer. Fixup time is the closest we can come to when
4696  * the actual transfer occurs. This happens during the masquerade after datastores are moved from old_chan
4697  * to new_chan. This is why new_chan is referenced for exten, context, and datastore information.
4698  *
4699  * At the end of this, we want to remove the datastore so that this fixup function is not called on any
4700  * future masquerades of the caller during the current call.
4701  */
4702 static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
4704  struct queue_transfer_ds *qtds = data;
4705  struct queue_ent *qe = qtds->qe;
4706  struct member *member = qtds->member;
4707  time_t callstart = qtds->starttime;
4708  int callcompletedinsl = qtds->callcompletedinsl;
4709  struct ast_datastore *datastore;
4710 
4711  ast_queue_log(qe->parent->name, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d",
4712  new_chan->exten, new_chan->context, (long) (callstart - qe->start),
4713  (long) (time(NULL) - callstart), qe->opos);
4714 
4715  update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart));
4716 
4717  /* No need to lock the channels because they are already locked in ast_do_masquerade */
4718  if ((datastore = ast_channel_datastore_find(old_chan, &queue_transfer_info, NULL))) {
4719  ast_channel_datastore_remove(old_chan, datastore);
4720  /* Datastore is freed in try_calling() */
4721  } else {
4722  ast_log(LOG_WARNING, "Can't find the queue_transfer datastore.\n");
4723  }
4724 }
4725 
4726 /*! \brief mechanism to tell if a queue caller was atxferred by a queue member.
4727  *
4728  * When a caller is atxferred, then the queue_transfer_info datastore
4729  * is removed from the channel. If it's still there after the bridge is
4730  * broken, then the caller was not atxferred.
4731  *
4732  * \note Only call this with chan locked
4733  */
4734 static int attended_transfer_occurred(struct ast_channel *chan)
4736  return ast_channel_datastore_find(chan, &queue_transfer_info, NULL) ? 0 : 1;
4737 }
4738 
4739 /*! \brief create a datastore for storing relevant info to log attended transfers in the queue_log
4740  */
4741 static struct ast_datastore *setup_transfer_datastore(struct queue_ent *qe, struct member *member, time_t starttime, int callcompletedinsl)
4743  struct ast_datastore *ds;
4744  struct queue_transfer_ds *qtds = ast_calloc(1, sizeof(*qtds));
4745 
4746  if (!qtds) {
4747  ast_log(LOG_WARNING, "Memory allocation error!\n");
4748  return NULL;
4749  }
4750 
4751  ast_channel_lock(qe->chan);
4752  if (!(ds = ast_datastore_alloc(&queue_transfer_info, NULL))) {
4753  ast_channel_unlock(qe->chan);
4754  ast_free(qtds);
4755  ast_log(LOG_WARNING, "Unable to create transfer datastore. queue_log will not show attended transfer\n");
4756  return NULL;
4757  }
4758 
4759  qtds->qe = qe;
4760  /* This member is refcounted in try_calling, so no need to add it here, too */
4761  qtds->member = member;
4762  qtds->starttime = starttime;
4764  ds->data = qtds;
4766  ast_channel_unlock(qe->chan);
4767  return ds;
4768 }
4769 
4770 struct queue_end_bridge {
4771  struct call_queue *q;
4773 };
4774 
4775 static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
4777  struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data;
4778  ao2_ref(qeb, +1);
4779  qeb->chan = originator;
4780 }
4781 
4782 static void end_bridge_callback(void *data)
4784  struct queue_end_bridge *qeb = data;
4785  struct call_queue *q = qeb->q;
4786  struct ast_channel *chan = qeb->chan;
4787 
4788  if (ao2_ref(qeb, -1) == 1) {
4789  set_queue_variables(q, chan);
4790  /* This unrefs the reference we made in try_calling when we allocated qeb */
4791  queue_t_unref(q, "Expire bridge_config reference");
4792  }
4793 }
4794 
4795 /*! \brief A large function which calls members, updates statistics, and bridges the caller and a member
4796  *
4797  * Here is the process of this function
4798  * 1. Process any options passed to the Queue() application. Options here mean the third argument to Queue()
4799  * 2. Iterate trough the members of the queue, creating a callattempt corresponding to each member. During this
4800  * iteration, we also check the dialed_interfaces datastore to see if we have already attempted calling this
4801  * member. If we have, we do not create a callattempt. This is in place to prevent call forwarding loops. Also
4802  * during each iteration, we call calc_metric to determine which members should be rung when.
4803  * 3. Call ring_one to place a call to the appropriate member(s)
4804  * 4. Call wait_for_answer to wait for an answer. If no one answers, return.
4805  * 5. Take care of any holdtime announcements, member delays, or other options which occur after a call has been answered.
4806  * 6. Start the monitor or mixmonitor if the option is set
4807  * 7. Remove the caller from the queue to allow other callers to advance
4808  * 8. Bridge the call.
4809  * 9. Do any post processing after the call has disconnected.
4810  *
4811  * \param[in] qe the queue_ent structure which corresponds to the caller attempting to reach members
4812  * \param[in] options the options passed as the third parameter to the Queue() application
4813  * \param[in] announceoverride filename to play to user when waiting
4814  * \param[in] url the url passed as the fourth parameter to the Queue() application
4815  * \param[in,out] tries the number of times we have tried calling queue members
4816  * \param[out] noption set if the call to Queue() has the 'n' option set.
4817  * \param[in] agi the agi passed as the fifth parameter to the Queue() application
4818  * \param[in] macro the macro passed as the sixth parameter to the Queue() application
4819  * \param[in] gosub the gosub passed as the seventh parameter to the Queue() application
4820  * \param[in] ringing 1 if the 'r' option is set, otherwise 0
4821  */
4822 static int try_calling(struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *tries, int *noption, const char *agi, const char *macro, const char *gosub, int ringing)
4824  struct member *cur;
4825  struct callattempt *outgoing = NULL; /* the list of calls we are building */
4826  int to, orig;
4827  char oldexten[AST_MAX_EXTENSION]="";
4828  char oldcontext[AST_MAX_CONTEXT]="";
4829  char queuename[256]="";
4830  char interfacevar[256]="";
4831  struct ast_channel *peer;
4832  struct ast_channel *which;
4833  struct callattempt *lpeer;
4834  struct member *member;
4835  struct ast_app *application;
4836  int res = 0, bridge = 0;
4837  int numbusies = 0;
4838  int x=0;
4839  char *announce = NULL;
4840  char digit = 0;
4841  time_t callstart;
4842  time_t now = time(NULL);
4843  struct ast_bridge_config bridge_config;
4844  char nondataquality = 1;
4845  char *agiexec = NULL;
4846  char *macroexec = NULL;
4847  char *gosubexec = NULL;
4848  const char *monitorfilename;
4849  const char *monitor_exec;
4850  const char *monitor_options;
4851  char tmpid[256], tmpid2[256];
4852  char meid[1024], meid2[1024];
4853  char mixmonargs[1512];
4854  struct ast_app *mixmonapp = NULL;
4855  char *p;
4856  char vars[2048];
4857  int forwardsallowed = 1;
4858  int block_connected_line = 0;
4859  int callcompletedinsl;
4860  struct ao2_iterator memi;
4861  struct ast_datastore *datastore, *transfer_ds;
4862  struct queue_end_bridge *queue_end_bridge = NULL;
4863 
4864  ast_channel_lock(qe->chan);
4865  datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL);
4866  ast_channel_unlock(qe->chan);
4867 
4868  memset(&bridge_config, 0, sizeof(bridge_config));
4869  tmpid[0] = 0;
4870  meid[0] = 0;
4871  time(&now);
4872 
4873  /* If we've already exceeded our timeout, then just stop
4874  * This should be extremely rare. queue_exec will take care
4875  * of removing the caller and reporting the timeout as the reason.
4876  */
4877  if (qe->expire && now >= qe->expire) {
4878  res = 0;
4879  goto out;
4880  }
4881 
4882  for (; options && *options; options++)
4883  switch (*options) {
4884  case 't':
4886  break;
4887  case 'T':
4889  break;
4890  case 'w':
4892  break;
4893  case 'W':
4895  break;
4896  case 'c':
4898  break;
4899  case 'd':
4900  nondataquality = 0;
4901  break;
4902  case 'h':
4904  break;
4905  case 'H':
4907  break;
4908  case 'k':
4910  break;
4911  case 'K':
4913  break;
4914  case 'n':
4916  (*tries)++;
4917  else
4918  *tries = ao2_container_count(qe->parent->members);
4919  *noption = 1;
4920  break;
4921  case 'i':
4922  forwardsallowed = 0;
4923  break;
4924  case 'I':
4925  block_connected_line = 1;
4926  break;
4927  case 'x':
4929  break;
4930  case 'X':
4932  break;
4933  case 'C':
4934  qe->cancel_answered_elsewhere = 1;
4935  break;
4936  }
4937 
4938  /* if the calling channel has the ANSWERED_ELSEWHERE flag set, make sure this is inherited.
4939  (this is mainly to support chan_local)
4940  */
4942  qe->cancel_answered_elsewhere = 1;
4943  }
4944 
4945  ao2_lock(qe->parent);
4946  ast_debug(1, "%s is trying to call a queue member.\n",
4947  qe->chan->name);
4948  ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
4949  if (!ast_strlen_zero(qe->announce))
4950  announce = qe->announce;
4951  if (!ast_strlen_zero(announceoverride))
4952  announce = announceoverride;
4953 
4954  memi = ao2_iterator_init(qe->parent->members, 0);
4955  while ((cur = ao2_iterator_next(&memi))) {
4956  struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
4957  struct ast_dialed_interface *di;
4958  AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces;
4959  if (!tmp) {
4960  ao2_ref(cur, -1);
4961  ao2_iterator_destroy(&memi);
4962  ao2_unlock(qe->parent);
4963  goto out;
4964  }
4965  if (!datastore) {
4966  if (!(datastore = ast_datastore_alloc(&dialed_interface_info, NULL))) {
4967  callattempt_free(tmp);
4968  ao2_ref(cur, -1);
4969  ao2_iterator_destroy(&memi);
4970  ao2_unlock(qe->parent);
4971  goto out;
4972  }
4974  if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) {
4975  callattempt_free(tmp);
4976  ao2_ref(cur, -1);
4977  ao2_iterator_destroy(&memi);
4978  ao2_unlock(qe->parent);
4979  goto out;
4980  }
4981  datastore->data = dialed_interfaces;
4982  AST_LIST_HEAD_INIT(dialed_interfaces);
4983 
4984  ast_channel_lock(qe->chan);
4985  ast_channel_datastore_add(qe->chan, datastore);
4986  ast_channel_unlock(qe->chan);
4987  } else
4988  dialed_interfaces = datastore->data;
4989 
4990  AST_LIST_LOCK(dialed_interfaces);
4991  AST_LIST_TRAVERSE(dialed_interfaces, di, list) {
4992  if (!strcasecmp(cur->interface, di->interface)) {
4993  ast_debug(1, "Skipping dialing interface '%s' since it has already been dialed\n",
4994  di->interface);
4995  break;
4996  }
4997  }
4998  AST_LIST_UNLOCK(dialed_interfaces);
4999 
5000  if (di) {
5001  callattempt_free(tmp);
5002  ao2_ref(cur, -1);
5003  continue;
5004  }
5005 
5006  /* It is always ok to dial a Local interface. We only keep track of
5007  * which "real" interfaces have been dialed. The Local channel will
5008  * inherit this list so that if it ends up dialing a real interface,
5009  * it won't call one that has already been called. */
5010  if (strncasecmp(cur->interface, "Local/", 6)) {
5011  if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) {
5012  callattempt_free(tmp);
5013  ao2_ref(cur, -1);
5014  ao2_iterator_destroy(&memi);
5015  ao2_unlock(qe->parent);
5016  goto out;
5017  }
5018  strcpy(di->interface, cur->interface);
5019 
5020  AST_LIST_LOCK(dialed_interfaces);
5021  AST_LIST_INSERT_TAIL(dialed_interfaces, di, list);
5022  AST_LIST_UNLOCK(dialed_interfaces);
5023  }
5024 
5025  /*
5026  * Seed the callattempt's connected line information with previously
5027  * acquired connected line info from the queued channel. The
5028  * previously acquired connected line info could have been set
5029  * through the CONNECTED_LINE dialplan function.
5030  */
5031  ast_channel_lock(qe->chan);
5033  ast_channel_unlock(qe->chan);
5034 
5035  tmp->block_connected_update = block_connected_line;
5036  tmp->stillgoing = 1;
5037  tmp->member = cur;/* Place the reference for cur into callattempt. */
5038  tmp->lastcall = cur->lastcall;
5039  tmp->lastqueue = cur->lastqueue;
5040  ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
5041  if (qe->tries == 0 && (cur->ringcount >= qe->parent->ringlimit)) {
5042  cur->ringcount = 0;
5043  }
5044  /* Special case: If we ring everyone, go ahead and ring them, otherwise
5045  just calculate their metric for the appropriate strategy */
5046  if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
5047  /* Put them in the list of outgoing thingies... We're ready now.
5048  XXX If we're forcibly removed, these outgoing calls won't get
5049  hung up XXX */
5050  tmp->q_next = outgoing;
5051  outgoing = tmp;
5052  /* If this line is up, don't try anybody else */
5053  if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
5054  break;
5055  } else {
5056  callattempt_free(tmp);
5057  }
5058  }
5059  ao2_iterator_destroy(&memi);
5060 
5062  /* Application arguments have higher timeout priority (behaviour for <=1.6) */
5063  if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout))
5064  to = (qe->expire - now) * 1000;
5065  else
5066  to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
5067  } else {
5068  /* Config timeout is higher priority thatn application timeout */
5069  if (qe->expire && qe->expire<=now) {
5070  to = 0;
5071  } else if (qe->parent->timeout) {
5072  to = qe->parent->timeout * 1000;
5073  } else {
5074  to = -1;
5075  }
5076  }
5077  orig = to;
5078  ++qe->pending;
5079  ++qe->tries;
5080  if (option_debug)
5081  ast_log(LOG_DEBUG, "%s is trying to ring one member from %s. This is try number %d\n",
5082  qe->chan->name, queuename, qe->tries);
5083  ao2_unlock(qe->parent);
5084  ring_one(qe, outgoing, &numbusies);
5085  lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies,
5087  forwardsallowed, ringing);
5088  /* The ast_channel_datastore_remove() function could fail here if the
5089  * datastore was moved to another channel during a masquerade. If this is
5090  * the case, don't free the datastore here because later, when the channel
5091  * to which the datastore was moved hangs up, it will attempt to free this
5092  * datastore again, causing a crash
5093  */
5094  ast_channel_lock(qe->chan);
5095  if (datastore && !ast_channel_datastore_remove(qe->chan, datastore)) {
5096  ast_datastore_free(datastore);
5097  }
5098  ast_channel_unlock(qe->chan);
5099  ao2_lock(qe->parent);
5101  store_next_rr(qe, outgoing);
5102 
5103  }
5104  if (qe->parent->strategy == QUEUE_STRATEGY_LINEAR) {
5105  store_next_lin(qe, outgoing);
5106  }
5107  ao2_unlock(qe->parent);
5108  peer = lpeer ? lpeer->chan : NULL;
5109  if (!peer) {
5110  qe->pending = 0;
5111  if (to) {
5112  /* Must gotten hung up */
5113  res = -1;
5114  } else {
5115  /* User exited by pressing a digit */
5116  res = digit;
5117  }
5118  if (option_debug && res == -1)
5119  ast_log(LOG_NOTICE, "%s: Nobody answered.\n", qe->chan->name);
5120  if (ast_cdr_isset_unanswered()) {
5121  /* channel contains the name of one of the outgoing channels
5122  in its CDR; zero out this CDR to avoid a dual-posting */
5123  struct callattempt *o;
5124  for (o = outgoing; o; o = o->q_next) {
5125  if (!o->chan) {
5126  continue;
5127  }
5128  if (strcmp(o->chan->cdr->dstchannel, qe->chan->cdr->dstchannel) == 0) {
5130  break;
5131  }
5132  }
5133  }
5134  } else { /* peer is valid */
5135  /* Ah ha! Someone answered within the desired timeframe. Of course after this
5136  we will always return with -1 so that it is hung up properly after the
5137  conversation. */
5138  if (!strcmp(qe->chan->tech->type, "DAHDI"))
5139  ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
5140  if (!strcmp(peer->tech->type, "DAHDI"))
5141  ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
5142  /* Update parameters for the queue */
5143  time(&now);
5144  recalc_holdtime(qe, (now - qe->start));
5145  ao2_lock(qe->parent);
5146  callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel);
5147  ao2_unlock(qe->parent);
5148  member = lpeer->member;
5149  /* Increment the refcount for this member, since we're going to be using it for awhile in here. */
5150  ao2_ref(member, 1);
5151  hangupcalls(outgoing, peer, qe->cancel_answered_elsewhere);
5152  outgoing = NULL;
5153  if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
5154  int res2;
5155 
5156  res2 = ast_autoservice_start(qe->chan);
5157  if (!res2) {
5158  if (qe->parent->memberdelay) {
5159  ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
5160  res2 = ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
5161  }
5162  if (!res2 && announce) {
5163  if (play_file(peer, announce) < 0) {
5164  ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", announce, peer->name);
5165  }
5166  }
5167  if (!res2 && qe->parent->reportholdtime) {
5168  if (!play_file(peer, qe->parent->sound_reporthold)) {
5169  int holdtime, holdtimesecs;
5170 
5171  time(&now);
5172  holdtime = abs((now - qe->start) / 60);
5173  holdtimesecs = abs((now - qe->start) % 60);
5174  if (holdtime > 0) {
5175  ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
5176  if (play_file(peer, qe->parent->sound_minutes) < 0) {
5177  ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_minutes, peer->name);
5178  }
5179  }
5180  if (holdtimesecs > 1) {
5181  ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, peer->language, NULL);
5182  if (play_file(peer, qe->parent->sound_seconds) < 0) {
5183  ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_seconds, peer->name);
5184  }
5185  }
5186  }
5187  }
5189  }
5190  if (ast_check_hangup(peer)) {
5191  /* Agent must have hung up */
5192  ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", peer->name);
5193  ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", "");
5194  if (qe->parent->eventwhencalled)
5195  manager_event(EVENT_FLAG_AGENT, "AgentDump",
5196  "Queue: %s\r\n"
5197  "Uniqueid: %s\r\n"
5198  "Channel: %s\r\n"
5199  "Member: %s\r\n"
5200  "MemberName: %s\r\n"
5201  "%s",
5202  queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
5203  qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
5204  ast_hangup(peer);
5205  ao2_ref(member, -1);
5206  goto out;
5207  } else if (ast_check_hangup(qe->chan)) {
5208  /* Caller must have hung up just before being connected */
5209  ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
5210  ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
5211  record_abandoned(qe);
5212  ast_hangup(peer);
5213  ao2_ref(member, -1);
5214  return -1;
5215  }
5216  }
5217  /* Stop music on hold */
5218  if (ringing)
5219  ast_indicate(qe->chan,-1);
5220  else
5221  ast_moh_stop(qe->chan);
5222  /* If appropriate, log that we have a destination channel */
5223  if (qe->chan->cdr)
5224  ast_cdr_setdestchan(qe->chan->cdr, peer->name);
5225  /* Make sure channels are compatible */
5226  res = ast_channel_make_compatible(qe->chan, peer);
5227  if (res < 0) {
5228  ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", "");
5229  ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
5230  record_abandoned(qe);
5231  ast_cdr_failed(qe->chan->cdr);
5232  ast_hangup(peer);
5233  ao2_ref(member, -1);
5234  return -1;
5235  }
5236 
5237  /* Play announcement to the caller telling it's his turn if defined */
5239  if (play_file(qe->chan, qe->parent->sound_callerannounce))
5240  ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", qe->parent->sound_callerannounce);
5241  }
5242 
5243  ao2_lock(qe->parent);
5244  /* if setinterfacevar is defined, make member variables available to the channel */
5245  /* use pbx_builtin_setvar to set a load of variables with one call */
5246  if (qe->parent->setinterfacevar) {
5247  snprintf(interfacevar, sizeof(interfacevar), "MEMBERINTERFACE=%s,MEMBERNAME=%s,MEMBERCALLS=%d,MEMBERLASTCALL=%ld,MEMBERPENALTY=%d,MEMBERDYNAMIC=%d,MEMBERREALTIME=%d",
5248  member->interface, member->membername, member->calls, (long)member->lastcall, member->penalty, member->dynamic, member->realtime);
5249  pbx_builtin_setvar_multiple(qe->chan, interfacevar);
5250  pbx_builtin_setvar_multiple(peer, interfacevar);
5251  }
5252 
5253  /* if setqueueentryvar is defined, make queue entry (i.e. the caller) variables available to the channel */
5254  /* use pbx_builtin_setvar to set a load of variables with one call */
5255  if (qe->parent->setqueueentryvar) {
5256  snprintf(interfacevar, sizeof(interfacevar), "QEHOLDTIME=%ld,QEORIGINALPOS=%d",
5257  (long) time(NULL) - qe->start, qe->opos);
5258  pbx_builtin_setvar_multiple(qe->chan, interfacevar);
5259  pbx_builtin_setvar_multiple(peer, interfacevar);
5260  }
5261 
5262  ao2_unlock(qe->parent);
5263 
5264  /* try to set queue variables if configured to do so*/
5265  set_queue_variables(qe->parent, qe->chan);
5266  set_queue_variables(qe->parent, peer);
5267 
5268  ast_channel_lock(qe->chan);
5269  if ((monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"))) {
5270  monitorfilename = ast_strdupa(monitorfilename);
5271  }
5272  ast_channel_unlock(qe->chan);
5273  /* Begin Monitoring */
5274  if (qe->parent->monfmt && *qe->parent->monfmt) {
5275  if (!qe->parent->montype) {
5276  const char *monexec;
5277  ast_debug(1, "Starting Monitor as requested.\n");
5278  ast_channel_lock(qe->chan);
5279  if ((monexec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC")) || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS")) {
5280  which = qe->chan;
5281  monexec = monexec ? ast_strdupa(monexec) : NULL;
5282  }
5283  else
5284  which = peer;
5285  ast_channel_unlock(qe->chan);
5286  if (monitorfilename) {
5287  ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1, X_REC_IN | X_REC_OUT);
5288  } else if (qe->chan->cdr) {
5289  ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1, X_REC_IN | X_REC_OUT);
5290  } else {
5291  /* Last ditch effort -- no CDR, make up something */
5292  snprintf(tmpid, sizeof(tmpid), "chan-%lx", (unsigned long)ast_random());
5293  ast_monitor_start(which, qe->parent->monfmt, tmpid, 1, X_REC_IN | X_REC_OUT);
5294  }
5295  if (!ast_strlen_zero(monexec)) {
5296  ast_monitor_setjoinfiles(which, 1);
5297  }
5298  } else {
5299  mixmonapp = pbx_findapp("MixMonitor");
5300 
5301  if (mixmonapp) {
5302  ast_debug(1, "Starting MixMonitor as requested.\n");
5303  if (!monitorfilename) {
5304  if (qe->chan->cdr)
5305  ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid));
5306  else
5307  snprintf(tmpid, sizeof(tmpid), "chan-%lx", (unsigned long)ast_random());
5308  } else {
5309  const char *m = monitorfilename;
5310  for (p = tmpid2; p < tmpid2 + sizeof(tmpid2) - 1; p++, m++) {
5311  switch (*m) {
5312  case '^':
5313  if (*(m + 1) == '{')
5314  *p = '$';
5315  break;
5316  case ',':
5317  *p++ = '\\';
5318  /* Fall through */
5319  default:
5320  *p = *m;
5321  }
5322  if (*m == '\0')
5323  break;
5324  }
5325  if (p == tmpid2 + sizeof(tmpid2))
5326  tmpid2[sizeof(tmpid2) - 1] = '\0';
5327 
5328  pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1);
5329  }
5330 
5331  ast_channel_lock(qe->chan);
5332  if ((monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"))) {
5333  monitor_exec = ast_strdupa(monitor_exec);
5334  }
5335  if ((monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"))) {
5336  monitor_options = ast_strdupa(monitor_options);
5337  } else {
5338  monitor_options = "";
5339  }
5340  ast_channel_unlock(qe->chan);
5341 
5342  if (monitor_exec) {
5343  const char *m = monitor_exec;
5344  for (p = meid2; p < meid2 + sizeof(meid2) - 1; p++, m++) {
5345  switch (*m) {
5346  case '^':
5347  if (*(m + 1) == '{')
5348  *p = '$';
5349  break;
5350  case ',':
5351  *p++ = '\\';
5352  /* Fall through */
5353  default:
5354  *p = *m;
5355  }
5356  if (*m == '\0')
5357  break;
5358  }
5359  if (p == meid2 + sizeof(meid2))
5360  meid2[sizeof(meid2) - 1] = '\0';
5361 
5362  pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1);
5363  }
5364 
5365  snprintf(tmpid2, sizeof(tmpid2), "%s.%s", tmpid, qe->parent->monfmt);
5366 
5367  if (!ast_strlen_zero(monitor_exec))
5368  snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s,%s", tmpid2, monitor_options, monitor_exec);
5369  else
5370  snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s", tmpid2, monitor_options);
5371 
5372  ast_debug(1, "Arguments being passed to MixMonitor: %s\n", mixmonargs);
5373  /* We purposely lock the CDR so that pbx_exec does not update the application data */
5374  if (qe->chan->cdr)
5376  pbx_exec(qe->chan, mixmonapp, mixmonargs);
5377  if (qe->chan->cdr)
5379 
5380  } else {
5381  ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n");
5382  }
5383  }
5384  }
5385  /* Drop out of the queue at this point, to prepare for next caller */
5386  leave_queue(qe);
5387  if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
5388  ast_debug(1, "app_queue: sendurl=%s.\n", url);
5389  ast_channel_sendurl(peer, url);
5390  }
5391 
5392  /* run a macro for this connection if defined. The macro simply returns, no action is taken on the result */
5393  /* use macro from dialplan if passed as a option, otherwise use the default queue macro */
5394  if (!ast_strlen_zero(macro)) {
5395  macroexec = ast_strdupa(macro);
5396  } else {
5397  if (qe->parent->membermacro)
5398  macroexec = ast_strdupa(qe->parent->membermacro);
5399  }
5400 
5401  if (!ast_strlen_zero(macroexec)) {
5402  ast_debug(1, "app_queue: macro=%s.\n", macroexec);
5403 
5404  res = ast_autoservice_start(qe->chan);
5405  if (res) {
5406  ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
5407  res = -1;
5408  }
5409 
5410  application = pbx_findapp("Macro");
5411 
5412  if (application) {
5413  res = pbx_exec(peer, application, macroexec);
5414  ast_debug(1, "Macro exited with status %d\n", res);
5415  res = 0;
5416  } else {
5417  ast_log(LOG_ERROR, "Could not find application Macro\n");
5418  res = -1;
5419  }
5420 
5421  if (ast_autoservice_stop(qe->chan) < 0) {
5422  ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
5423  res = -1;
5424  }
5425  }
5426 
5427  /* run a gosub for this connection if defined. The gosub simply returns, no action is taken on the result */
5428  /* use gosub from dialplan if passed as a option, otherwise use the default queue gosub */
5429  if (!ast_strlen_zero(gosub)) {
5430  gosubexec = ast_strdupa(gosub);
5431  } else {
5432  if (qe->parent->membergosub)
5433  gosubexec = ast_strdupa(qe->parent->membergosub);
5434  }
5435 
5436  if (!ast_strlen_zero(gosubexec)) {
5437  ast_debug(1, "app_queue: gosub=%s.\n", gosubexec);
5438 
5439  res = ast_autoservice_start(qe->chan);
5440  if (res) {
5441  ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
5442  res = -1;
5443  }
5444 
5445  application = pbx_findapp("Gosub");
5446 
5447  if (application) {
5448  char *gosub_args, *gosub_argstart;
5449 
5450  /* Set where we came from */
5451  ast_copy_string(peer->context, "app_queue_gosub_virtual_context", sizeof(peer->context));
5452  ast_copy_string(peer->exten, "s", sizeof(peer->exten));
5453  peer->priority = 0;
5454 
5455  gosub_argstart = strchr(gosubexec, ',');
5456  if (gosub_argstart) {
5457  const char *what_is_s = "s";
5458  *gosub_argstart = 0;
5459  if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL)) &&
5460  ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL))) {
5461  what_is_s = "~~s~~";
5462  }
5463  if (ast_asprintf(&gosub_args, "%s,%s,1(%s)", gosubexec, what_is_s, gosub_argstart + 1) < 0) {
5464  gosub_args = NULL;
5465  }
5466  *gosub_argstart = ',';
5467  } else {
5468  const char *what_is_s = "s";
5469  if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL)) &&
5470  ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL))) {
5471  what_is_s = "~~s~~";
5472  }
5473  if (ast_asprintf(&gosub_args, "%s,%s,1", gosubexec, what_is_s) < 0) {
5474  gosub_args = NULL;
5475  }
5476  }
5477  if (gosub_args) {
5478  res = pbx_exec(peer, application, gosub_args);
5479  if (!res) {
5480  struct ast_pbx_args args;
5481  memset(&args, 0, sizeof(args));
5482  args.no_hangup_chan = 1;
5483  ast_pbx_run_args(peer, &args);
5484  }
5485  ast_free(gosub_args);
5486  ast_debug(1, "Gosub exited with status %d\n", res);
5487  } else {
5488  ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n");
5489  }
5490  } else {
5491  ast_log(LOG_ERROR, "Could not find application Gosub\n");
5492  res = -1;
5493  }
5494 
5495  if (ast_autoservice_stop(qe->chan) < 0) {
5496  ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
5497  res = -1;
5498  }
5499  }
5500 
5501  if (!ast_strlen_zero(agi)) {
5502  ast_debug(1, "app_queue: agi=%s.\n", agi);
5503  application = pbx_findapp("agi");
5504  if (application) {
5505  agiexec = ast_strdupa(agi);
5506  pbx_exec(qe->chan, application, agiexec);
5507  } else
5508  ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
5509  }
5510  qe->handled++;
5511  ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s|%ld", (long) time(NULL) - qe->start, peer->uniqueid,
5512  (long)(orig - to > 0 ? (orig - to) / 1000 : 0));
5513 
5514  if (qe->chan->cdr) {
5515  struct ast_cdr *cdr;
5516  struct ast_cdr *newcdr;
5517 
5518  /* Only work with the last CDR in the stack*/
5519  cdr = qe->chan->cdr;
5520  while (cdr->next) {
5521  cdr = cdr->next;
5522  }
5523 
5524  /* If this CDR is not related to us add new one*/
5525  if ((strcasecmp(cdr->uniqueid, qe->chan->uniqueid)) &&
5526  (strcasecmp(cdr->linkedid, qe->chan->uniqueid)) &&
5527  (newcdr = ast_cdr_dup(cdr))) {
5528  ast_channel_lock(qe->chan);
5529  ast_cdr_init(newcdr, qe->chan);
5530  ast_cdr_reset(newcdr, 0);
5531  cdr = ast_cdr_append(cdr, newcdr);
5532  cdr = cdr->next;
5533  ast_channel_unlock(qe->chan);
5534  }
5535 
5536  if (update_cdr) {
5537  ast_copy_string(cdr->dstchannel, member->membername, sizeof(cdr->dstchannel));
5538  }
5539  }
5540 
5541  if (qe->parent->eventwhencalled)
5542  manager_event(EVENT_FLAG_AGENT, "AgentConnect",
5543  "Queue: %s\r\n"
5544  "Uniqueid: %s\r\n"
5545  "Channel: %s\r\n"
5546  "Member: %s\r\n"
5547  "MemberName: %s\r\n"
5548  "Holdtime: %ld\r\n"
5549  "BridgedChannel: %s\r\n"
5550  "Ringtime: %ld\r\n"
5551  "%s",
5552  queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
5553  (long) time(NULL) - qe->start, peer->uniqueid, (long)(orig - to > 0 ? (orig - to) / 1000 : 0),
5554  qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
5555  ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
5556  ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
5557 
5558  if ((queue_end_bridge = ao2_alloc(sizeof(*queue_end_bridge), NULL))) {
5559  queue_end_bridge->q = qe->parent;
5560  queue_end_bridge->chan = qe->chan;
5561  bridge_config.end_bridge_callback = end_bridge_callback;
5562  bridge_config.end_bridge_callback_data = queue_end_bridge;
5564  /* Since queue_end_bridge can survive beyond the life of this call to Queue, we need
5565  * to make sure to increase the refcount of this queue so it cannot be freed until we
5566  * are done with it. We remove this reference in end_bridge_callback.
5567  */
5568  queue_t_ref(qe->parent, "For bridge_config reference");
5569  }
5570 
5571  time(&callstart);
5572  transfer_ds = setup_transfer_datastore(qe, member, callstart, callcompletedinsl);
5573  bridge = ast_bridge_call(qe->chan, peer, &bridge_config);
5574 
5575  /* If the queue member did an attended transfer, then the TRANSFER already was logged in the queue_log
5576  * when the masquerade occurred. These other "ending" queue_log messages are unnecessary, except for
5577  * the AgentComplete manager event
5578  */
5579  ast_channel_lock(qe->chan);
5580  if (!attended_transfer_occurred(qe->chan)) {
5581  struct ast_datastore *tds;
5582 
5583  /* detect a blind transfer */
5584  if (!(qe->chan->_softhangup | peer->_softhangup) && (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten))) {
5585  ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d",
5586  qe->chan->exten, qe->chan->context, (long) (callstart - qe->start),
5587  (long) (time(NULL) - callstart), qe->opos);
5588  send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER);
5589  } else if (ast_check_hangup(qe->chan) && !ast_check_hangup(peer)) {
5590  ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d",
5591  (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
5592  send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), CALLER);
5593  } else {
5594  ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d",
5595  (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
5596  send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), AGENT);
5597  }
5598  if ((tds = ast_channel_datastore_find(qe->chan, &queue_transfer_info, NULL))) {
5600  /* tds was added by setup_transfer_datastore() and is freed below. */
5601  }
5602  ast_channel_unlock(qe->chan);
5603  update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart));
5604  } else {
5605  ast_channel_unlock(qe->chan);
5606 
5607  /* We already logged the TRANSFER on the queue_log, but we still need to send the AgentComplete event */
5608  send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER);
5609  }
5610 
5611  if (transfer_ds) {
5612  ast_datastore_free(transfer_ds);
5613  }
5614  ast_hangup(peer);
5615  res = bridge ? bridge : 1;
5616  ao2_ref(member, -1);
5617  }
5618 out:
5619  hangupcalls(outgoing, NULL, qe->cancel_answered_elsewhere);
5620 
5621  return res;
5622 }
5623 
5624 static int wait_a_bit(struct queue_ent *qe)
5626  /* Don't need to hold the lock while we setup the outgoing calls */
5627  int retrywait = qe->parent->retry * 1000;
5628 
5629  int res = ast_waitfordigit(qe->chan, retrywait);
5630  if (res > 0 && !valid_exit(qe, res))
5631  res = 0;
5632 
5633  return res;
5634 }
5635 
5636 static struct member *interface_exists(struct call_queue *q, const char *interface)
5638  struct member *mem;
5639  struct ao2_iterator mem_iter;
5640 
5641  if (!q)
5642  return NULL;
5643 
5644  mem_iter = ao2_iterator_init(q->members, 0);
5645  while ((mem = ao2_iterator_next(&mem_iter))) {
5646  if (!strcasecmp(interface, mem->interface)) {
5647  ao2_iterator_destroy(&mem_iter);
5648  return mem;
5649  }
5650  ao2_ref(mem, -1);
5651  }
5652  ao2_iterator_destroy(&mem_iter);
5653 
5654  return NULL;
5655 }
5656 
5657 
5658 /*! \brief Dump all members in a specific queue to the database
5659  *
5660  * <pm_family>/<queuename> = <interface>;<penalty>;<paused>;<state_interface>[|...]
5661  */
5662 static void dump_queue_members(struct call_queue *pm_queue)
5664  struct member *cur_member;
5665  struct ast_str *value;
5666  struct ao2_iterator mem_iter;
5667 
5668  if (!pm_queue) {
5669  return;
5670  }
5671 
5672  /* 4K is a reasonable default for most applications, but we grow to
5673  * accommodate more if necessary. */
5674  if (!(value = ast_str_create(4096))) {
5675  return;
5676  }
5677 
5678  mem_iter = ao2_iterator_init(pm_queue->members, 0);
5679  while ((cur_member = ao2_iterator_next(&mem_iter))) {
5680  if (!cur_member->dynamic) {
5681  ao2_ref(cur_member, -1);
5682  continue;
5683  }
5684 
5685  ast_str_append(&value, 0, "%s%s;%d;%d;%s;%s",
5686  ast_str_strlen(value) ? "|" : "",
5687  cur_member->interface,
5688  cur_member->penalty,
5689  cur_member->paused,
5690  cur_member->membername,
5691  cur_member->state_interface);
5692 
5693  ao2_ref(cur_member, -1);
5694  }
5695  ao2_iterator_destroy(&mem_iter);
5696 
5697  if (ast_str_strlen(value) && !cur_member) {
5698  if (ast_db_put(pm_family, pm_queue->name, ast_str_buffer(value)))
5699  ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
5700  } else {
5701  /* Delete the entry if the queue is empty or there is an error */
5702  ast_db_del(pm_family, pm_queue->name);
5703  }
5704 
5705  ast_free(value);
5706 }
5707 
5708 /*! \brief Remove member from queue
5709  * \retval RES_NOT_DYNAMIC when they aren't a RT member
5710  * \retval RES_NOSUCHQUEUE queue does not exist
5711  * \retval RES_OKAY removed member from queue
5712  * \retval RES_EXISTS queue exists but no members
5713 */
5714 static int remove_from_queue(const char *queuename, const char *interface)
5716  struct call_queue *q, tmpq = {
5717  .name = queuename,
5718  };
5719  struct member *mem, tmpmem;
5720  int res = RES_NOSUCHQUEUE;
5721 
5722  ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
5723  if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Temporary reference for interface removal"))) {
5724  ao2_lock(q);
5725  if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
5726  /* XXX future changes should beware of this assumption!! */
5727  if (!mem->dynamic) {
5728  ao2_ref(mem, -1);
5729  ao2_unlock(q);
5730  queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference");
5731  return RES_NOT_DYNAMIC;
5732  }
5733  manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
5734  "Queue: %s\r\n"
5735  "Location: %s\r\n"
5736  "MemberName: %s\r\n",
5737  q->name, mem->interface, mem->membername);
5738  member_remove_from_queue(q, mem);
5739  ao2_ref(mem, -1);
5740 
5741  if (queue_persistent_members)
5742  dump_queue_members(q);
5743 
5744  res = RES_OKAY;
5745  } else {
5746  res = RES_EXISTS;
5747  }
5748  ao2_unlock(q);
5749  queue_t_unref(q, "Expiring temporary reference");
5750  }
5751 
5752  return res;
5753 }
5754 
5755 /*! \brief Add member to queue
5756  * \retval RES_NOT_DYNAMIC when they aren't a RT member
5757  * \retval RES_NOSUCHQUEUE queue does not exist
5758  * \retval RES_OKAY added member from queue
5759  * \retval RES_EXISTS queue exists but no members
5760  * \retval RES_OUT_OF_MEMORY queue exists but not enough memory to create member
5761 */
5762 static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface)
5764  struct call_queue *q;
5765  struct member *new_member, *old_member;
5766  int res = RES_NOSUCHQUEUE;
5767 
5768  /*! \note Ensure the appropriate realtime queue is loaded. Note that this
5769  * short-circuits if the queue is already in memory. */
5770  if (!(q = load_realtime_queue(queuename)))
5771  return res;
5772 
5773  ao2_lock(q);
5774  if ((old_member = interface_exists(q, interface)) == NULL) {
5775  if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) {
5776  new_member->dynamic = 1;
5777  member_add_to_queue(q, new_member);
5778  manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
5779  "Queue: %s\r\n"
5780  "Location: %s\r\n"
5781  "MemberName: %s\r\n"
5782  "Membership: %s\r\n"
5783  "Penalty: %d\r\n"
5784  "CallsTaken: %d\r\n"
5785  "LastCall: %d\r\n"
5786  "Status: %d\r\n"
5787  "Paused: %d\r\n",
5788  q->name, new_member->interface, new_member->membername,
5789  "dynamic",
5790  new_member->penalty, new_member->calls, (int) new_member->lastcall,
5791  new_member->status, new_member->paused);
5792 
5793  ao2_ref(new_member, -1);
5794  new_member = NULL;
5795 
5796  if (dump)
5797  dump_queue_members(q);
5798 
5799  res = RES_OKAY;
5800  } else {
5801  res = RES_OUTOFMEMORY;
5802  }
5803  } else {
5804  ao2_ref(old_member, -1);
5805  res = RES_EXISTS;
5806  }
5807  ao2_unlock(q);
5808  queue_t_unref(q, "Expiring temporary reference");
5809 
5810  return res;
5811 }
5812 
5813 static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
5815  int found = 0;
5816  struct call_queue *q;
5817  struct member *mem;
5818  struct ao2_iterator queue_iter;
5819  int failed;
5820 
5821  /* Special event for when all queues are paused - individual events still generated */
5822  /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */
5823  if (ast_strlen_zero(queuename))
5824  ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
5825 
5826  queue_iter = ao2_iterator_init(queues, 0);
5827  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate over queues"))) {
5828  ao2_lock(q);
5829  if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
5830  if ((mem = interface_exists(q, interface))) {
5831  if (mem->paused == paused) {
5832  ast_debug(1, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
5833  }
5834 
5835  failed = 0;
5836  if (mem->realtime) {
5837  failed = update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0");
5838  }
5839 
5840  if (failed) {
5841  ast_log(LOG_WARNING, "Failed %spausing realtime queue member %s:%s\n", (paused ? "" : "un"), q->name, interface);
5842  ao2_ref(mem, -1);
5843  ao2_unlock(q);
5844  queue_t_unref(q, "Done with iterator");
5845  continue;
5846  }
5847  found++;
5848  mem->paused = paused;
5849 
5850  if (queue_persistent_members)
5851  dump_queue_members(q);
5852 
5853  ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", S_OR(reason, ""));
5854 
5855  if (!ast_strlen_zero(reason)) {
5856  manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
5857  "Queue: %s\r\n"
5858  "Location: %s\r\n"
5859  "MemberName: %s\r\n"
5860  "Paused: %d\r\n"
5861  "Reason: %s\r\n",
5862  q->name, mem->interface, mem->membername, paused, reason);
5863  } else {
5864  manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
5865  "Queue: %s\r\n"
5866  "Location: %s\r\n"
5867  "MemberName: %s\r\n"
5868  "Paused: %d\r\n",
5869  q->name, mem->interface, mem->membername, paused);
5870  }
5871  ao2_ref(mem, -1);
5872  }
5873  }
5874 
5875  if (!ast_strlen_zero(queuename) && !strcasecmp(queuename, q->name)) {
5876  ao2_unlock(q);
5877  queue_t_unref(q, "Done with iterator");
5878  break;
5879  }
5880 
5881  ao2_unlock(q);
5882  queue_t_unref(q, "Done with iterator");
5883  }
5884  ao2_iterator_destroy(&queue_iter);
5885 
5886  return found ? RESULT_SUCCESS : RESULT_FAILURE;
5887 }
5888 
5889 /* \brief Sets members penalty, if queuename=NULL we set member penalty in all the queues. */
5890 static int set_member_penalty(const char *queuename, const char *interface, int penalty)
5892  int foundinterface = 0, foundqueue = 0;
5893  struct call_queue *q;
5894  struct member *mem;
5895  struct ao2_iterator queue_iter;
5896 
5897  if (penalty < 0) {
5898  ast_log(LOG_ERROR, "Invalid penalty (%d)\n", penalty);
5899  return RESULT_FAILURE;
5900  }
5901 
5902  queue_iter = ao2_iterator_init(queues, 0);
5903  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
5904  ao2_lock(q);
5905  if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
5906  foundqueue++;
5907  if ((mem = interface_exists(q, interface))) {
5908  foundinterface++;
5909  mem->penalty = penalty;
5910 
5911  ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty);
5912  manager_event(EVENT_FLAG_AGENT, "QueueMemberPenalty",
5913  "Queue: %s\r\n"
5914  "Location: %s\r\n"
5915  "Penalty: %d\r\n",
5916  q->name, mem->interface, penalty);
5917  ao2_ref(mem, -1);
5918  }
5919  }
5920  ao2_unlock(q);
5921  queue_t_unref(q, "Done with iterator");
5922  }
5923  ao2_iterator_destroy(&queue_iter);
5924 
5925  if (foundinterface) {
5926  return RESULT_SUCCESS;
5927  } else if (!foundqueue) {
5928  ast_log (LOG_ERROR, "Invalid queuename\n");
5929  } else {
5930  ast_log (LOG_ERROR, "Invalid interface\n");
5931  }
5932 
5933  return RESULT_FAILURE;
5934 }
5935 
5936 /* \brief Gets members penalty.
5937  * \return Return the members penalty or RESULT_FAILURE on error.
5938 */
5939 static int get_member_penalty(char *queuename, char *interface)
5941  int foundqueue = 0, penalty;
5942  struct call_queue *q, tmpq = {
5943  .name = queuename,
5944  };
5945  struct member *mem;
5946 
5947  if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Search for queue"))) {
5948  foundqueue = 1;
5949  ao2_lock(q);
5950  if ((mem = interface_exists(q, interface))) {
5951  penalty = mem->penalty;
5952  ao2_ref(mem, -1);
5953  ao2_unlock(q);
5954  queue_t_unref(q, "Search complete");
5955  return penalty;
5956  }
5957  ao2_unlock(q);
5958  queue_t_unref(q, "Search complete");
5959  }
5960 
5961  /* some useful debuging */
5962  if (foundqueue)
5963  ast_log (LOG_ERROR, "Invalid queuename\n");
5964  else
5965  ast_log (LOG_ERROR, "Invalid interface\n");
5966 
5967  return RESULT_FAILURE;
5968 }
5969 
5970 /*! \brief Reload dynamic queue members persisted into the astdb */
5971 static void reload_queue_members(void)
5973  char *cur_ptr;
5974  const char *queue_name;
5975  char *member;
5976  char *interface;
5977  char *membername = NULL;
5978  char *state_interface;
5979  char *penalty_tok;
5980  int penalty = 0;
5981  char *paused_tok;
5982  int paused = 0;
5983  struct ast_db_entry *db_tree;
5984  struct ast_db_entry *entry;
5985  struct call_queue *cur_queue;
5986  char *queue_data;
5987 
5988  /* Each key in 'pm_family' is the name of a queue */
5989  db_tree = ast_db_gettree(pm_family, NULL);
5990  for (entry = db_tree; entry; entry = entry->next) {
5991 
5992  queue_name = entry->key + strlen(pm_family) + 2;
5993 
5994  {
5995  struct call_queue tmpq = {
5996  .name = queue_name,
5997  };
5998  cur_queue = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Reload queue members");
5999  }
6000 
6001  if (!cur_queue)
6002  cur_queue = load_realtime_queue(queue_name);
6003 
6004  if (!cur_queue) {
6005  /* If the queue no longer exists, remove it from the
6006  * database */
6007  ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
6008  ast_db_del(pm_family, queue_name);
6009  continue;
6010  }
6011 
6012  if (ast_db_get_allocated(pm_family, queue_name, &queue_data)) {
6013  queue_t_unref(cur_queue, "Expire reload reference");
6014  continue;
6015  }
6016 
6017  cur_ptr = queue_data;
6018  while ((member = strsep(&cur_ptr, ",|"))) {
6019  if (ast_strlen_zero(member))
6020  continue;
6021 
6022  interface = strsep(&member, ";");
6023  penalty_tok = strsep(&member, ";");
6024  paused_tok = strsep(&member, ";");
6025  membername = strsep(&member, ";");
6026  state_interface = strsep(&member, ";");
6027 
6028  if (!penalty_tok) {
6029  ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
6030  break;
6031  }
6032  penalty = strtol(penalty_tok, NULL, 10);
6033  if (errno == ERANGE) {
6034  ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
6035  break;
6036  }
6037 
6038  if (!paused_tok) {
6039  ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
6040  break;
6041  }
6042  paused = strtol(paused_tok, NULL, 10);
6043  if ((errno == ERANGE) || paused < 0 || paused > 1) {
6044  ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
6045  break;
6046  }
6047 
6048  ast_debug(1, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name, interface, membername, penalty, paused);
6049 
6050  if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface) == RES_OUTOFMEMORY) {
6051  ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
6052  break;
6053  }
6054  }
6055  queue_t_unref(cur_queue, "Expire reload reference");
6056  ast_free(queue_data);
6057  }
6058 
6059  if (db_tree) {
6060  ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
6061  ast_db_freetree(db_tree);
6062  }
6063 }
6064 
6065 /*! \brief PauseQueueMember application */
6066 static int pqm_exec(struct ast_channel *chan, const char *data)
6068  char *parse;
6070  AST_APP_ARG(queuename);
6071  AST_APP_ARG(interface);
6072  AST_APP_ARG(options);
6073  AST_APP_ARG(reason);
6074  );
6075 
6076  if (ast_strlen_zero(data)) {
6077  ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n");
6078  return -1;
6079  }
6080 
6081  parse = ast_strdupa(data);
6082 
6083  AST_STANDARD_APP_ARGS(args, parse);
6084 
6085  if (ast_strlen_zero(args.interface)) {
6086  ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
6087  return -1;
6088  }
6089 
6090  if (set_member_paused(args.queuename, args.interface, args.reason, 1)) {
6091  ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
6092  pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
6093  return 0;
6094  }
6095 
6096  pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
6097 
6098  return 0;
6099 }
6100 
6101 /*! \brief UnPauseQueueMember application */
6102 static int upqm_exec(struct ast_channel *chan, const char *data)
6104  char *parse;
6106  AST_APP_ARG(queuename);
6107  AST_APP_ARG(interface);
6108  AST_APP_ARG(options);
6109  AST_APP_ARG(reason);
6110  );
6111 
6112  if (ast_strlen_zero(data)) {
6113  ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename],interface[,options[,reason]])\n");
6114  return -1;
6115  }
6116 
6117  parse = ast_strdupa(data);
6118 
6119  AST_STANDARD_APP_ARGS(args, parse);
6120 
6121  if (ast_strlen_zero(args.interface)) {
6122  ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
6123  return -1;
6124  }
6125 
6126  if (set_member_paused(args.queuename, args.interface, args.reason, 0)) {
6127  ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
6128  pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
6129  return 0;
6130  }
6131 
6132  pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
6133 
6134  return 0;
6135 }
6136 
6137 /*! \brief RemoveQueueMember application */
6138 static int rqm_exec(struct ast_channel *chan, const char *data)
6140  int res=-1;
6141  char *parse, *temppos = NULL;
6143  AST_APP_ARG(queuename);
6144  AST_APP_ARG(interface);
6145  );
6146 
6147 
6148  if (ast_strlen_zero(data)) {
6149  ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface])\n");
6150  return -1;
6151  }
6152 
6153  parse = ast_strdupa(data);
6154 
6155  AST_STANDARD_APP_ARGS(args, parse);
6156 
6157  if (ast_strlen_zero(args.interface)) {
6158  args.interface = ast_strdupa(chan->name);
6159  temppos = strrchr(args.interface, '-');
6160  if (temppos)
6161  *temppos = '\0';
6162  }
6163 
6164  ast_debug(1, "queue: %s, member: %s\n", args.queuename, args.interface);
6165 
6166  switch (remove_from_queue(args.queuename, args.interface)) {
6167  case RES_OKAY:
6168  ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", "");
6169  ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
6170  pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
6171  res = 0;
6172  break;
6173  case RES_EXISTS:
6174  ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
6175  pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
6176  res = 0;
6177  break;
6178  case RES_NOSUCHQUEUE:
6179  ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
6180  pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
6181  res = 0;
6182  break;
6183  case RES_NOT_DYNAMIC:
6184  ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface);
6185  pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC");
6186  res = 0;
6187  break;
6188  }
6189 
6190  return res;
6191 }
6192 
6193 /*! \brief AddQueueMember application */
6194 static int aqm_exec(struct ast_channel *chan, const char *data)
6196  int res=-1;
6197  char *parse, *temppos = NULL;
6199  AST_APP_ARG(queuename);
6200  AST_APP_ARG(interface);
6201  AST_APP_ARG(penalty);
6202  AST_APP_ARG(options);
6203  AST_APP_ARG(membername);
6204  AST_APP_ARG(state_interface);
6205  );
6206  int penalty = 0;
6207 
6208  if (ast_strlen_zero(data)) {
6209  ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface]]]]])\n");
6210  return -1;
6211  }
6212 
6213  parse = ast_strdupa(data);
6214 
6215  AST_STANDARD_APP_ARGS(args, parse);
6216 
6217  if (ast_strlen_zero(args.interface)) {
6218  args.interface = ast_strdupa(chan->name);
6219  temppos = strrchr(args.interface, '-');
6220  if (temppos)
6221  *temppos = '\0';
6222  }
6223 
6224  if (!ast_strlen_zero(args.penalty)) {
6225  if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) {
6226  ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
6227  penalty = 0;
6228  }
6229  }
6230 
6231  switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) {
6232  case RES_OKAY:
6233  ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", "");
6234  ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
6235  pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
6236  res = 0;
6237  break;
6238  case RES_EXISTS:
6239  ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
6240  pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
6241  res = 0;
6242  break;
6243  case RES_NOSUCHQUEUE:
6244  ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
6245  pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
6246  res = 0;
6247  break;
6248  case RES_OUTOFMEMORY:
6249  ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename);
6250  break;
6251  }
6252 
6253  return res;
6254 }
6255 
6256 /*! \brief QueueLog application */
6257 static int ql_exec(struct ast_channel *chan, const char *data)
6259  char *parse;
6260 
6262  AST_APP_ARG(queuename);
6263  AST_APP_ARG(uniqueid);
6264  AST_APP_ARG(membername);
6265  AST_APP_ARG(event);
6266  AST_APP_ARG(params);
6267  );
6268 
6269  if (ast_strlen_zero(data)) {
6270  ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n");
6271  return -1;
6272  }
6273 
6274  parse = ast_strdupa(data);
6275 
6276  AST_STANDARD_APP_ARGS(args, parse);
6277 
6278  if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
6279  || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
6280  ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n");
6281  return -1;
6282  }
6283 
6284  ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event,
6285  "%s", args.params ? args.params : "");
6286 
6287  return 0;
6288 }
6289 
6290 /*! \brief Copy rule from global list into specified queue */
6291 static void copy_rules(struct queue_ent *qe, const char *rulename)
6293  struct penalty_rule *pr_iter;
6294  struct rule_list *rl_iter;
6295  const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename;
6297  AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
6298  if (!strcasecmp(rl_iter->name, tmp))
6299  break;
6300  }
6301  if (rl_iter) {
6302  AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
6303  struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr));
6304  if (!new_pr) {
6305  ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n");
6306  break;
6307  }
6308  new_pr->time = pr_iter->time;
6309  new_pr->max_value = pr_iter->max_value;
6310  new_pr->min_value = pr_iter->min_value;
6311  new_pr->max_relative = pr_iter->max_relative;
6312  new_pr->min_relative = pr_iter->min_relative;
6313  AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list);
6314  }
6315  }
6317 }
6318 
6319 /*!\brief The starting point for all queue calls
6320  *
6321  * The process involved here is to
6322  * 1. Parse the options specified in the call to Queue()
6323  * 2. Join the queue
6324  * 3. Wait in a loop until it is our turn to try calling a queue member
6325  * 4. Attempt to call a queue member
6326  * 5. If 4. did not result in a bridged call, then check for between
6327  * call options such as periodic announcements etc.
6328  * 6. Try 4 again unless some condition (such as an expiration time) causes us to
6329  * exit the queue.
6330  */
6331 static int queue_exec(struct ast_channel *chan, const char *data)
6333  int res=-1;
6334  int ringing=0;
6335  const char *user_priority;
6336  const char *max_penalty_str;
6337  const char *min_penalty_str;
6338  int prio;
6339  int qcontinue = 0;
6340  int max_penalty, min_penalty;
6341  enum queue_result reason = QUEUE_UNKNOWN;
6342  /* whether to exit Queue application after the timeout hits */
6343  int tries = 0;
6344  int noption = 0;
6345  char *parse;
6346  int makeannouncement = 0;
6347  int position = 0;
6349  AST_APP_ARG(queuename);
6350  AST_APP_ARG(options);
6351  AST_APP_ARG(url);
6352  AST_APP_ARG(announceoverride);
6353  AST_APP_ARG(queuetimeoutstr);
6354  AST_APP_ARG(agi);
6355  AST_APP_ARG(macro);
6356  AST_APP_ARG(gosub);
6357  AST_APP_ARG(rule);
6358  AST_APP_ARG(position);
6359  );
6360  /* Our queue entry */
6361  struct queue_ent qe = { 0 };
6362 
6363  if (ast_strlen_zero(data)) {
6364  ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,macro[,gosub[,rule[,position]]]]]]]]]\n");
6365  return -1;
6366  }
6367 
6368  parse = ast_strdupa(data);
6369  AST_STANDARD_APP_ARGS(args, parse);
6370 
6371  /* Setup our queue entry */
6372  qe.start = time(NULL);
6373 
6374  /* set the expire time based on the supplied timeout; */
6375  if (!ast_strlen_zero(args.queuetimeoutstr))
6376  qe.expire = qe.start + atoi(args.queuetimeoutstr);
6377  else
6378  qe.expire = 0;
6379 
6380  /* Get the priority from the variable ${QUEUE_PRIO} */
6381  ast_channel_lock(chan);
6382  user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
6383  if (user_priority) {
6384  if (sscanf(user_priority, "%30d", &prio) == 1) {
6385  ast_debug(1, "%s: Got priority %d from ${QUEUE_PRIO}.\n", chan->name, prio);
6386  } else {
6387  ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
6388  user_priority, chan->name);
6389  prio = 0;
6390  }
6391  } else {
6392  ast_debug(3, "NO QUEUE_PRIO variable found. Using default.\n");
6393  prio = 0;
6394  }
6395 
6396  /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
6397 
6398  if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
6399  if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) {
6400  ast_debug(1, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", chan->name, max_penalty);
6401  } else {
6402  ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
6403  max_penalty_str, chan->name);
6404  max_penalty = INT_MAX;
6405  }
6406  } else {
6407  max_penalty = INT_MAX;
6408  }
6409 
6410  if ((min_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MIN_PENALTY"))) {
6411  if (sscanf(min_penalty_str, "%30d", &min_penalty) == 1) {
6412  ast_debug(1, "%s: Got min penalty %d from ${QUEUE_MIN_PENALTY}.\n", chan->name, min_penalty);
6413  } else {
6414  ast_log(LOG_WARNING, "${QUEUE_MIN_PENALTY}: Invalid value (%s), channel %s.\n",
6415  min_penalty_str, chan->name);
6416  min_penalty = INT_MAX;
6417  }
6418  } else {
6419  min_penalty = INT_MAX;
6420  }
6421  ast_channel_unlock(chan);
6422 
6423  if (args.options && (strchr(args.options, 'r')))
6424  ringing = 1;
6425 
6426  if (ringing != 1 && args.options && (strchr(args.options, 'R'))) {
6427  qe.ring_when_ringing = 1;
6428  }
6429 
6430  if (args.options && (strchr(args.options, 'c')))
6431  qcontinue = 1;
6432 
6433  if (args.position) {
6434  position = atoi(args.position);
6435  if (position < 0) {
6436  ast_log(LOG_WARNING, "Invalid position '%s' given for call to queue '%s'. Assuming no preference for position\n", args.position, args.queuename);
6437  position = 0;
6438  }
6439  }
6440 
6441  ast_debug(1, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
6442  args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio);
6443 
6444  qe.chan = chan;
6445  qe.prio = prio;
6446  qe.max_penalty = max_penalty;
6447  qe.min_penalty = min_penalty;
6448  qe.last_pos_said = 0;
6449  qe.last_pos = 0;
6450  qe.last_periodic_announce_time = time(NULL);
6452  qe.valid_digits = 0;
6453  if (join_queue(args.queuename, &qe, &reason, position)) {
6454  ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
6455  set_queue_result(chan, reason);
6456  return 0;
6457  }
6458  ast_assert(qe.parent != NULL);
6459 
6460  ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s|%d",
6461  S_OR(args.url, ""),
6462  S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, ""),
6463  qe.opos);
6464  copy_rules(&qe, args.rule);
6465  qe.pr = AST_LIST_FIRST(&qe.qe_rules);
6466 check_turns:
6467  if (ringing) {
6469  } else {
6470  ast_moh_start(chan, qe.moh, NULL);
6471  }
6472 
6473  /* This is the wait loop for callers 2 through maxlen */
6474  res = wait_our_turn(&qe, ringing, &reason);
6475  if (res) {
6476  goto stop;
6477  }
6478 
6479  makeannouncement = 0;
6480 
6481  for (;;) {
6482  /* This is the wait loop for the head caller*/
6483  /* To exit, they may get their call answered; */
6484  /* they may dial a digit from the queue context; */
6485  /* or, they may timeout. */
6486 
6487  /* Leave if we have exceeded our queuetimeout */
6488  if (qe.expire && (time(NULL) >= qe.expire)) {
6489  record_abandoned(&qe);
6490  reason = QUEUE_TIMEOUT;
6491  res = 0;
6492  ast_queue_log(args.queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld",
6493  qe.pos, qe.opos, (long) time(NULL) - qe.start);
6494  break;
6495  }
6496 
6497  if (makeannouncement) {
6498  /* Make a position announcement, if enabled */
6499  if (qe.parent->announcefrequency)
6500  if ((res = say_position(&qe,ringing)))
6501  goto stop;
6502  }
6503  makeannouncement = 1;
6504 
6505  /* Make a periodic announcement, if enabled */
6507  if ((res = say_periodic_announcement(&qe,ringing)))
6508  goto stop;
6509 
6510  /* Leave if we have exceeded our queuetimeout */
6511  if (qe.expire && (time(NULL) >= qe.expire)) {
6512  record_abandoned(&qe);
6513  reason = QUEUE_TIMEOUT;
6514  res = 0;
6515  ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
6516  break;
6517  }
6518 
6519  /* see if we need to move to the next penalty level for this queue */
6520  while (qe.pr && ((time(NULL) - qe.start) > qe.pr->time)) {
6521  update_qe_rule(&qe);
6522  }
6523 
6524  /* Try calling all queue members for 'timeout' seconds */
6525  res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi, args.macro, args.gosub, ringing);
6526  if (res) {
6527  goto stop;
6528  }
6529 
6530  if (qe.parent->leavewhenempty) {
6531  int status = 0;
6532  if ((status = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty, qe.parent->leavewhenempty, 0))) {
6533  record_abandoned(&qe);
6534  reason = QUEUE_LEAVEEMPTY;
6535  ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
6536  res = 0;
6537  break;
6538  }
6539  }
6540 
6541  /* exit after 'timeout' cycle if 'n' option enabled */
6542  if (noption && tries >= ao2_container_count(qe.parent->members)) {
6543  ast_verb(3, "Exiting on time-out cycle\n");
6544  ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
6545  record_abandoned(&qe);
6546  reason = QUEUE_TIMEOUT;
6547  res = 0;
6548  break;
6549  }
6550 
6551 
6552  /* Leave if we have exceeded our queuetimeout */
6553  if (qe.expire && (time(NULL) >= qe.expire)) {
6554  record_abandoned(&qe);
6555  reason = QUEUE_TIMEOUT;
6556  res = 0;
6557  ast_queue_log(qe.parent->name, qe.chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", qe.pos, qe.opos, (long) time(NULL) - qe.start);
6558  break;
6559  }
6560 
6561  /* If using dynamic realtime members, we should regenerate the member list for this queue */
6563  /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
6564  res = wait_a_bit(&qe);
6565  if (res)
6566  goto stop;
6567 
6568  /* Since this is a priority queue and
6569  * it is not sure that we are still at the head
6570  * of the queue, go and check for our turn again.
6571  */
6572  if (!is_our_turn(&qe)) {
6573  ast_debug(1, "Darn priorities, going back in queue (%s)!\n", qe.chan->name);
6574  goto check_turns;
6575  }
6576  }
6577 
6578 stop:
6579  if (res) {
6580  if (res < 0) {
6581  if (!qe.handled) {
6582  record_abandoned(&qe);
6583  ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON",
6584  "%d|%d|%ld", qe.pos, qe.opos,
6585  (long) time(NULL) - qe.start);
6586  res = -1;
6587  } else if (qcontinue) {
6588  reason = QUEUE_CONTINUE;
6589  res = 0;
6590  }
6591  } else if (qe.valid_digits) {
6592  ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY",
6593  "%s|%d|%d|%ld", qe.digits, qe.pos, qe.opos, (long) time(NULL) - qe.start);
6594  }
6595  }
6596 
6597  /* Don't allow return code > 0 */
6598  if (res >= 0) {
6599  res = 0;
6600  if (ringing) {
6601  ast_indicate(chan, -1);
6602  } else {
6603  ast_moh_stop(chan);
6604  }
6605  ast_stopstream(chan);
6606  }
6607 
6609 
6610  leave_queue(&qe);
6611  if (reason != QUEUE_UNKNOWN)
6612  set_queue_result(chan, reason);
6613 
6614  /*
6615  * every queue_ent is given a reference to it's parent
6616  * call_queue when it joins the queue. This ref must be taken
6617  * away right before the queue_ent is destroyed. In this case
6618  * the queue_ent is about to be returned on the stack
6619  */
6620  qe.parent = queue_unref(qe.parent);
6621 
6622  return res;
6623 }
6624 
6625 /*!
6626  * \brief create interface var with all queue details.
6627  * \retval 0 on success
6628  * \retval -1 on error
6629 */
6630 static int queue_function_var(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
6632  int res = -1;
6633  struct call_queue *q, tmpq = {
6634  .name = data,
6635  };
6636 
6637  char interfacevar[256] = "";
6638  float sl = 0;
6639 
6640  if (ast_strlen_zero(data)) {
6641  ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
6642  return -1;
6643  }
6644 
6645  if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE() function"))) {
6646  ao2_lock(q);
6647  if (q->setqueuevar) {
6648  sl = 0;
6649  res = 0;
6650 
6651  if (q->callscompleted > 0) {
6652  sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
6653  }
6654 
6655  snprintf(interfacevar, sizeof(interfacevar),
6656  "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
6658 
6659  pbx_builtin_setvar_multiple(chan, interfacevar);
6660  }
6661 
6662  ao2_unlock(q);
6663  queue_t_unref(q, "Done with QUEUE() function");
6664  } else {
6665  ast_log(LOG_WARNING, "queue %s was not found\n", data);
6666  }
6667 
6668  snprintf(buf, len, "%d", res);
6669 
6670  return 0;
6671 }
6672 
6673 /*!
6674  * \brief Check if a given queue exists
6675  *
6676  */
6677 static int queue_function_exists(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
6679  struct call_queue *q;
6680 
6681  buf[0] = '\0';
6682 
6683  if (ast_strlen_zero(data)) {
6684  ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
6685  return -1;
6686  }
6687  q = load_realtime_queue(data);
6688  snprintf(buf, len, "%d", q != NULL? 1 : 0);
6689  if (q) {
6690  queue_t_unref(q, "Done with temporary reference in QUEUE_EXISTS()");
6691  }
6692 
6693  return 0;
6694 }
6695 
6696 /*!
6697  * \brief Get number either busy / free / ready or total members of a specific queue
6698  * \retval number of members (busy / free / ready / total)
6699  * \retval -1 on error
6700 */
6701 static int queue_function_qac(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
6703  int count = 0;
6704  struct member *m;
6705  struct ao2_iterator mem_iter;
6706  struct call_queue *q;
6707  char *option;
6708 
6709  if (ast_strlen_zero(data)) {
6710  ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
6711  return -1;
6712  }
6713 
6714  if ((option = strchr(data, ',')))
6715  *option++ = '\0';
6716  else
6717  option = "logged";
6718  if ((q = load_realtime_queue(data))) {
6719  ao2_lock(q);
6720  if (!strcasecmp(option, "logged")) {
6721  mem_iter = ao2_iterator_init(q->members, 0);
6722  while ((m = ao2_iterator_next(&mem_iter))) {
6723  /* Count the agents who are logged in and presently answering calls */
6724  if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
6725  count++;
6726  }
6727  ao2_ref(m, -1);
6728  }
6729  ao2_iterator_destroy(&mem_iter);
6730  } else if (!strcasecmp(option, "free")) {
6731  mem_iter = ao2_iterator_init(q->members, 0);
6732  while ((m = ao2_iterator_next(&mem_iter))) {
6733  /* Count the agents who are logged in and presently answering calls */
6734  if (((m->status == AST_DEVICE_NOT_INUSE) || (m->status == AST_DEVICE_UNKNOWN)) && (!m->paused)) {
6735  count++;
6736  }
6737  ao2_ref(m, -1);
6738  }
6739  ao2_iterator_destroy(&mem_iter);
6740  } else if (!strcasecmp(option, "ready")) {
6741  time_t now;
6742  time(&now);
6743  mem_iter = ao2_iterator_init(q->members, 0);
6744  while ((m = ao2_iterator_next(&mem_iter))) {
6745  /* Count the agents who are logged in, not paused and not wrapping up */
6746  if (((m->status == AST_DEVICE_NOT_INUSE) || (m->status == AST_DEVICE_UNKNOWN)) && (!m->paused) &&
6747  !(m->lastcall && q->wrapuptime && ((now - q->wrapuptime) < m->lastcall))) {
6748  count++;
6749  }
6750  ao2_ref(m, -1);
6751  }
6752  ao2_iterator_destroy(&mem_iter);
6753  } else if (!strcasecmp(option, "paused")) {
6754  mem_iter = ao2_iterator_init(q->members, 0);
6755  while ((m = ao2_iterator_next(&mem_iter))) {
6756  /* Count paused members */
6757  if (m->paused) {
6758  count++;
6759  }
6760  ao2_ref(m, -1);
6761  }
6762  ao2_iterator_destroy(&mem_iter);
6763  } else /* must be "count" */
6764  count = ao2_container_count(q->members);
6765  ao2_unlock(q);
6766  queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()");
6767  } else
6768  ast_log(LOG_WARNING, "queue %s was not found\n", data);
6769 
6770  snprintf(buf, len, "%d", count);
6771 
6772  return 0;
6773 }
6774 
6775 /*!
6776  * \brief Get the total number of members in a specific queue (Deprecated)
6777  * \retval number of members
6778  * \retval -1 on error
6779 */
6780 static int queue_function_qac_dep(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
6782  int count = 0;
6783  struct member *m;
6784  struct call_queue *q;
6785  struct ao2_iterator mem_iter;
6786  static int depflag = 1;
6787 
6788  if (depflag) {
6789  depflag = 0;
6790  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");
6791  }
6792 
6793  if (ast_strlen_zero(data)) {
6794  ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
6795  return -1;
6796  }
6797 
6798  if ((q = load_realtime_queue(data))) {
6799  ao2_lock(q);
6800  mem_iter = ao2_iterator_init(q->members, 0);
6801  while ((m = ao2_iterator_next(&mem_iter))) {
6802  /* Count the agents who are logged in and presently answering calls */
6803  if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
6804  count++;
6805  }
6806  ao2_ref(m, -1);
6807  }
6808  ao2_iterator_destroy(&mem_iter);
6809  ao2_unlock(q);
6810  queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER_COUNT");
6811  } else
6812  ast_log(LOG_WARNING, "queue %s was not found\n", data);
6813 
6814  snprintf(buf, len, "%d", count);
6815 
6816  return 0;
6817 }
6818 
6819 /*! \brief Dialplan function QUEUE_WAITING_COUNT() Get number callers waiting in a specific queue */
6820 static int queue_function_queuewaitingcount(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
6822  int count = 0;
6823  struct call_queue *q, tmpq = {
6824  .name = data,
6825  };
6826  struct ast_variable *var = NULL;
6827 
6828  buf[0] = '\0';
6829 
6830  if (ast_strlen_zero(data)) {
6831  ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n");
6832  return -1;
6833  }
6834 
6835  if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_WAITING_COUNT()"))) {
6836  ao2_lock(q);
6837  count = q->count;
6838  ao2_unlock(q);
6839  queue_t_unref(q, "Done with reference in QUEUE_WAITING_COUNT()");
6840  } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) {
6841  /* if the queue is realtime but was not found in memory, this
6842  * means that the queue had been deleted from memory since it was
6843  * "dead." This means it has a 0 waiting count
6844  */
6845  count = 0;
6846  ast_variables_destroy(var);
6847  } else
6848  ast_log(LOG_WARNING, "queue %s was not found\n", data);
6849 
6850  snprintf(buf, len, "%d", count);
6851 
6852  return 0;
6853 }
6854 
6855 /*! \brief Dialplan function QUEUE_MEMBER_LIST() Get list of members in a specific queue */
6856 static int queue_function_queuememberlist(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
6858  struct call_queue *q, tmpq = {
6859  .name = data,
6860  };
6861  struct member *m;
6862 
6863  /* Ensure an otherwise empty list doesn't return garbage */
6864  buf[0] = '\0';
6865 
6866  if (ast_strlen_zero(data)) {
6867  ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
6868  return -1;
6869  }
6870 
6871  if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_MEMBER_LIST()"))) {
6872  int buflen = 0, count = 0;
6873  struct ao2_iterator mem_iter;
6874 
6875  ao2_lock(q);
6876  mem_iter = ao2_iterator_init(q->members, 0);
6877  while ((m = ao2_iterator_next(&mem_iter))) {
6878  /* strcat() is always faster than printf() */
6879  if (count++) {
6880  strncat(buf + buflen, ",", len - buflen - 1);
6881  buflen++;
6882  }
6883  strncat(buf + buflen, m->interface, len - buflen - 1);
6884  buflen += strlen(m->interface);
6885  /* Safeguard against overflow (negative length) */
6886  if (buflen >= len - 2) {
6887  ao2_ref(m, -1);
6888  ast_log(LOG_WARNING, "Truncating list\n");
6889  break;
6890  }
6891  ao2_ref(m, -1);
6892  }
6893  ao2_iterator_destroy(&mem_iter);
6894  ao2_unlock(q);
6895  queue_t_unref(q, "Done with QUEUE_MEMBER_LIST()");
6896  } else
6897  ast_log(LOG_WARNING, "queue %s was not found\n", data);
6898 
6899  /* We should already be terminated, but let's make sure. */
6900  buf[len - 1] = '\0';
6901 
6902  return 0;
6903 }
6904 
6905 /*! \brief Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty. */
6906 static int queue_function_memberpenalty_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
6908  int penalty;
6910  AST_APP_ARG(queuename);
6911  AST_APP_ARG(interface);
6912  );
6913  /* Make sure the returned value on error is NULL. */
6914  buf[0] = '\0';
6915 
6916  if (ast_strlen_zero(data)) {
6917  ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
6918  return -1;
6919  }
6920 
6921  AST_STANDARD_APP_ARGS(args, data);
6922 
6923  if (args.argc < 2) {
6924  ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
6925  return -1;
6926  }
6927 
6928  penalty = get_member_penalty (args.queuename, args.interface);
6929 
6930  if (penalty >= 0) /* remember that buf is already '\0' */
6931  snprintf (buf, len, "%d", penalty);
6932 
6933  return 0;
6934 }
6935 
6936 /*! \brief Dialplan function QUEUE_MEMBER_PENALTY() Sets the members penalty. */
6937 static int queue_function_memberpenalty_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
6939  int penalty;
6941  AST_APP_ARG(queuename);
6942  AST_APP_ARG(interface);
6943  );
6944 
6945  if (ast_strlen_zero(data)) {
6946  ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
6947  return -1;
6948  }
6949 
6950  AST_STANDARD_APP_ARGS(args, data);
6951 
6952  if (args.argc < 2) {
6953  ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
6954  return -1;
6955  }
6956 
6957  penalty = atoi(value);
6958 
6959  if (ast_strlen_zero(args.interface)) {
6960  ast_log (LOG_ERROR, "<interface> parameter can't be null\n");
6961  return -1;
6962  }
6963 
6964  /* if queuename = NULL then penalty will be set for interface in all the queues. */
6965  if (set_member_penalty(args.queuename, args.interface, penalty)) {
6966  ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n");
6967  return -1;
6968  }
6969 
6970  return 0;
6971 }
6972 
6973 static int queue_function_queuememberstatus(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
6975  struct ast_module_user *lu;
6976  struct call_queue *q;
6977  struct member *cur;
6978  struct ao2_iterator queue_iter;
6979  struct ao2_iterator mem_iter;
6980  char tmp[128] = "";
6981  char *buffer;
6982 
6984  AST_APP_ARG(queue);
6985  AST_APP_ARG(interface);
6986  );
6987 
6988  AST_STANDARD_APP_ARGS(args, data);
6989  if (ast_strlen_zero(args.interface)) {
6990  ast_log(LOG_WARNING, "This function requires an interface name.\n");
6991  return -1;
6992  }
6993  lu = ast_module_user_add(chan);
6994 
6995  buffer = ast_malloc(len);
6996  buffer[0]='\0';
6997 
6998  queue_iter = ao2_iterator_init(queues,0);
6999  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
7000  ao2_lock(q);
7001  if (ast_strlen_zero(args.queue) ||
7002  (!ast_strlen_zero(args.queue) && !strncmp(args.queue, q->name, strlen(args.queue)))
7003  ) {
7004  /* Iterate over queue members */
7005  mem_iter = ao2_iterator_init(q->members, 0);
7006  while ((cur = ao2_iterator_next(&mem_iter))) {
7007  if (!strncasecmp(args.interface, cur->membername, strlen(args.interface))) {
7008  if (!ast_strlen_zero(args.queue)) {
7009  ast_copy_string(buffer, ast_devstate2str(cur->status), len);
7010  } else {
7011  snprintf(tmp, sizeof(tmp), "%s%s:%s", ast_strlen_zero(tmp)?"":",", q->name, ast_devstate2str(cur->status));
7012  strncat(buffer, tmp, sizeof(tmp));
7013  }
7014  ao2_ref(cur, -1);
7015  continue;
7016  }
7017  ao2_ref(cur, -1);
7018  }
7019  ao2_iterator_destroy(&mem_iter);
7020  }
7021  ao2_unlock(q);
7022  queue_t_unref(q, "Done with iterator");
7023  }
7024  ao2_iterator_destroy(&queue_iter);
7025  ast_copy_string(buf, buffer, len);
7026  ast_free(buffer);
7027 
7029  return 0;
7030 }
7031 
7032 static int queue_function_queuememberpaused(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
7034  struct ast_module_user *lu;
7035  struct call_queue *q;
7036  struct member *cur;
7037  struct ao2_iterator queue_iter;
7038  struct ao2_iterator mem_iter;
7039  char tmp[128] = "";
7040  char *buffer;
7041 
7043  AST_APP_ARG(queue);
7044  AST_APP_ARG(interface);
7045  );
7046 
7047  AST_STANDARD_APP_ARGS(args, data);
7048  if (ast_strlen_zero(args.interface)) {
7049  ast_log(LOG_WARNING, "This function requires an interface name.\n");
7050  return -1;
7051  }
7052  lu = ast_module_user_add(chan);
7053 
7054  buffer = ast_malloc(len);
7055  buffer[0]='\0';
7056 
7057  queue_iter = ao2_iterator_init(queues,0);
7058  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
7059  ao2_lock(q);
7060  if (ast_strlen_zero(args.queue) ||
7061  (!ast_strlen_zero(args.queue) && !strncmp(args.queue, q->name, strlen(args.queue)))
7062  ) {
7063  /* Iterate over queue members */
7064  mem_iter = ao2_iterator_init(q->members, 0);
7065  while ((cur = ao2_iterator_next(&mem_iter))) {
7066  if (!strncasecmp(args.interface, cur->membername, strlen(args.interface))) {
7067  if (!ast_strlen_zero(args.queue)) {
7068  ast_copy_string(buffer, cur->paused?"1":"0", len);
7069  } else {
7070  snprintf(tmp, sizeof(tmp), "%s%s:%s", ast_strlen_zero(tmp)?"":",", q->name, cur->paused?"1":"0");
7071  strncat(buffer, tmp, sizeof(tmp));
7072  }
7073  ao2_ref(cur, -1);
7074  break;
7075  }
7076  ao2_ref(cur, -1);
7077  }
7078  ao2_iterator_destroy(&mem_iter);
7079  }
7080  ao2_unlock(q);
7081  queue_t_unref(q, "Done with iterator");
7082  }
7083  ao2_iterator_destroy(&queue_iter);
7084  ast_copy_string(buf, buffer, len);
7085  ast_free(buffer);
7086 
7088  return 0;
7089 }
7090 
7091 static struct ast_custom_function queueexists_function = {
7092  .name = "QUEUE_EXISTS",
7093  .read = queue_function_exists,
7094 };
7095 
7096 static struct ast_custom_function queuevar_function = {
7097  .name = "QUEUE_VARIABLES",
7098  .read = queue_function_var,
7099 };
7100 
7102  .name = "QUEUE_MEMBER",
7103  .read = queue_function_qac,
7104 };
7105 
7106 static struct ast_custom_function queuemembercount_dep = {
7107  .name = "QUEUE_MEMBER_COUNT",
7108  .read = queue_function_qac_dep,
7109 };
7110 
7112  .name = "QUEUE_WAITING_COUNT",
7114 };
7115 
7117  .name = "QUEUE_MEMBER_LIST",
7119 };
7120 
7122  .name = "QUEUE_MEMBER_PENALTY",
7125 };
7126 
7128  .name = "QUEUE_MEMBER_STATUS",
7130 };
7131 
7133  .name = "QUEUE_MEMBER_PAUSED",
7135 };
7136 
7137 /*! \brief Reload the rules defined in queuerules.conf
7138  *
7139  * \param reload If 1, then only process queuerules.conf if the file
7140  * has changed since the last time we inspected it.
7141  * \return Always returns AST_MODULE_LOAD_SUCCESS
7142  */
7143 static int reload_queue_rules(int reload)
7145  struct ast_config *cfg;
7146  struct rule_list *rl_iter, *new_rl;
7147  struct penalty_rule *pr_iter;
7148  char *rulecat = NULL;
7149  struct ast_variable *rulevar = NULL;
7150  struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
7151 
7152  if (!(cfg = ast_config_load("queuerules.conf", config_flags))) {
7153  ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n");
7154  return AST_MODULE_LOAD_SUCCESS;
7155  } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
7156  ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n");
7157  return AST_MODULE_LOAD_SUCCESS;
7158  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
7159  ast_log(LOG_ERROR, "Config file queuerules.conf is in an invalid format. Aborting.\n");
7160  return AST_MODULE_LOAD_SUCCESS;
7161  }
7162 
7164  while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) {
7165  while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list)))
7166  ast_free(pr_iter);
7167  ast_free(rl_iter);
7168  }
7169  while ((rulecat = ast_category_browse(cfg, rulecat))) {
7170  if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
7172  ast_config_destroy(cfg);
7173  return AST_MODULE_LOAD_FAILURE;
7174  } else {
7175  ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
7176  AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
7177  for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next)
7178  if(!strcasecmp(rulevar->name, "penaltychange"))
7179  insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno);
7180  else
7181  ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno);
7182  }
7183  }
7185 
7186  ast_config_destroy(cfg);
7187 
7188  return AST_MODULE_LOAD_SUCCESS;
7189 }
7190 
7191 /*! Set the global queue parameters as defined in the "general" section of queues.conf */
7192 static void queue_set_global_params(struct ast_config *cfg)
7194  const char *general_val = NULL;
7195  queue_debug = 0;
7196  if ((general_val = ast_variable_retrieve(cfg, "general", "debug")))
7197  queue_debug = ast_true(general_val);
7198  queue_persistent_members = 0;
7199  if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
7200  queue_persistent_members = ast_true(general_val);
7201  autofill_default = 0;
7202  if ((general_val = ast_variable_retrieve(cfg, "general", "autofill")))
7203  autofill_default = ast_true(general_val);
7204  montype_default = 0;
7205  if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) {
7206  if (!strcasecmp(general_val, "mixmonitor"))
7207  montype_default = 1;
7208  }
7209  update_cdr = 0;
7210  if ((general_val = ast_variable_retrieve(cfg, "general", "updatecdr")))
7211  update_cdr = ast_true(general_val);
7212  shared_lastcall = 0;
7213  if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall")))
7214  shared_lastcall = ast_true(general_val);
7215 }
7216 
7217 /*! \brief reload information pertaining to a single member
7218  *
7219  * This function is called when a member = line is encountered in
7220  * queues.conf.
7221  *
7222  * \param memberdata The part after member = in the config file
7223  * \param q The queue to which this member belongs
7224  */
7225 static void reload_single_member(const char *memberdata, struct call_queue *q)
7227  char *membername, *interface, *state_interface, *tmp;
7228  char *parse;
7229  struct member *cur, *newm;
7230  struct member tmpmem;
7231  int penalty;
7233  AST_APP_ARG(interface);
7234  AST_APP_ARG(penalty);
7235  AST_APP_ARG(membername);
7236  AST_APP_ARG(state_interface);
7237  );
7238 
7239  if (ast_strlen_zero(memberdata)) {
7240  ast_log(LOG_WARNING, "Empty queue member definition. Moving on!\n");
7241  return;
7242  }
7243 
7244  /* Add a new member */
7245  parse = ast_strdupa(memberdata);
7246 
7247  AST_STANDARD_APP_ARGS(args, parse);
7248 
7249  interface = args.interface;
7250  if (!ast_strlen_zero(args.penalty)) {
7251  tmp = args.penalty;
7252  ast_strip(tmp);
7253  penalty = atoi(tmp);
7254  if (penalty < 0) {
7255  penalty = 0;
7256  }
7257  } else {
7258  penalty = 0;
7259  }
7260 
7261  if (!ast_strlen_zero(args.membername)) {
7262  membername = args.membername;
7263  ast_strip(membername);
7264  } else {
7265  membername = interface;
7266  }
7267 
7268  if (!ast_strlen_zero(args.state_interface)) {
7269  state_interface = args.state_interface;
7270  ast_strip(state_interface);
7271  } else {
7272  state_interface = interface;
7273  }
7274 
7275  /* Find the old position in the list */
7276  ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
7277  cur = ao2_find(q->members, &tmpmem, OBJ_POINTER);
7278 
7279  if ((newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface))) {
7280  if (cur) {
7281  /* Round Robin Queue Position must be copied if this is replacing an existing member */
7282  ao2_lock(q->members);
7283  newm->queuepos = cur->queuepos;
7284  ao2_link(q->members, newm);
7285  ao2_unlink(q->members, cur);
7286  ao2_unlock(q->members);
7287  } else {
7288  /* Otherwise we need to add using the function that will apply a round robin queue position manually. */
7289  member_add_to_queue(q, newm);
7290  }
7291  ao2_ref(newm, -1);
7292  }
7293  newm = NULL;
7294 
7295  if (cur) {
7296  ao2_ref(cur, -1);
7297  }
7298 }
7299 
7300 static int mark_member_dead(void *obj, void *arg, int flags)
7302  struct member *member = obj;
7303  if (!member->dynamic && !member->realtime) {
7304  member->delme = 1;
7305  }
7306  return 0;
7307 }
7308 
7309 static int kill_dead_members(void *obj, void *arg, int flags)
7311  struct member *member = obj;
7312 
7313  if (!member->delme) {
7314  member->status = get_queue_member_status(member);
7315  return 0;
7316  } else {
7317  return CMP_MATCH;
7318  }
7319 }
7320 
7321 /*! \brief Reload information pertaining to a particular queue
7322  *
7323  * Once we have isolated a queue within reload_queues, we call this. This will either
7324  * reload information for the queue or if we're just reloading member information, we'll just
7325  * reload that without touching other settings within the queue
7326  *
7327  * \param cfg The configuration which we are reading
7328  * \param mask Tells us what information we need to reload
7329  * \param queuename The name of the queue we are reloading information from
7330  * \retval void
7331  */
7332 static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask, const char *queuename)
7334  int new;
7335  struct call_queue *q = NULL;
7336  /*We're defining a queue*/
7337  struct call_queue tmpq = {
7338  .name = queuename,
7339  };
7340  const char *tmpvar;
7341  const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
7342  const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER);
7343  int prev_weight = 0;
7344  struct ast_variable *var;
7345  if (!(q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find queue for reload"))) {
7346  if (queue_reload) {
7347  /* Make one then */
7348  if (!(q = alloc_queue(queuename))) {
7349  return;
7350  }
7351  } else {
7352  /* Since we're not reloading queues, this means that we found a queue
7353  * in the configuration file which we don't know about yet. Just return.
7354  */
7355  return;
7356  }
7357  new = 1;
7358  } else {
7359  new = 0;
7360  }
7361 
7362  if (!new) {
7363  ao2_lock(q);
7364  prev_weight = q->weight ? 1 : 0;
7365  }
7366  /* Check if we already found a queue with this name in the config file */
7367  if (q->found) {
7368  ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", queuename);
7369  if (!new) {
7370  /* It should be impossible to *not* hit this case*/
7371  ao2_unlock(q);
7372  }
7373  queue_t_unref(q, "We exist! Expiring temporary pointer");
7374  return;
7375  }
7376  /* Due to the fact that the "linear" strategy will have a different allocation
7377  * scheme for queue members, we must devise the queue's strategy before other initializations.
7378  * To be specific, the linear strategy needs to function like a linked list, meaning the ao2
7379  * container used will have only a single bucket instead of the typical number.
7380  */
7381  if (queue_reload) {
7382  if ((tmpvar = ast_variable_retrieve(cfg, queuename, "strategy"))) {
7383  q->strategy = strat2int(tmpvar);
7384  if (q->strategy < 0) {
7385  ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
7386  tmpvar, q->name);
7388  }
7389  } else {
7391  }
7392  init_queue(q);
7393  }
7394  if (member_reload) {
7396  q->found = 1;
7397  }
7398  for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
7399  if (member_reload && !strcasecmp(var->name, "member")) {
7400  reload_single_member(var->value, q);
7401  } else if (queue_reload) {
7402  queue_set_param(q, var->name, var->value, var->lineno, 1);
7403  }
7404  }
7405  /* At this point, we've determined if the queue has a weight, so update use_weight
7406  * as appropriate
7407  */
7408  if (!q->weight && prev_weight) {
7409  ast_atomic_fetchadd_int(&use_weight, -1);
7410  }
7411  else if (q->weight && !prev_weight) {
7412  ast_atomic_fetchadd_int(&use_weight, +1);
7413  }
7414 
7415  /* Free remaining members marked as delme */
7416  if (member_reload) {
7417  ao2_lock(q->members);
7420  ao2_unlock(q->members);
7421  }
7422 
7423  if (new) {
7424  queues_t_link(queues, q, "Add queue to container");
7425  } else {
7426  ao2_unlock(q);
7427  }
7428  queue_t_unref(q, "Expiring creation reference");
7429 }
7430 
7431 static int remove_members_and_mark_unfound(void *obj, void *arg, int flags)
7433  struct call_queue *q = obj;
7434  char *queuename = arg;
7435  if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
7436  q->found = 0;
7437 
7438  }
7439  return 0;
7440 }
7441 
7442 static int mark_dead_and_unfound(void *obj, void *arg, int flags)
7444  struct call_queue *q = obj;
7445  char *queuename = arg;
7446  if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
7447  q->dead = 1;
7448  q->found = 0;
7449  }
7450  return 0;
7451 }
7452 
7453 static int kill_dead_queues(void *obj, void *arg, int flags)
7455  struct call_queue *q = obj;
7456  char *queuename = arg;
7457  if ((ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name)) && q->dead) {
7458  return CMP_MATCH;
7459  } else {
7460  return 0;
7461  }
7462 }
7463 
7464 /*! \brief reload the queues.conf file
7465  *
7466  * This function reloads the information in the general section of the queues.conf
7467  * file and potentially more, depending on the value of mask.
7468  *
7469  * \param reload 0 if we are calling this the first time, 1 every other time
7470  * \param mask Gives flags telling us what information to actually reload
7471  * \param queuename If set to a non-zero string, then only reload information from
7472  * that particular queue. Otherwise inspect all queues
7473  * \retval -1 Failure occurred
7474  * \retval 0 All clear!
7475  */
7476 static int reload_queues(int reload, struct ast_flags *mask, const char *queuename)
7478  struct ast_config *cfg;
7479  char *cat;
7480  struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
7481  const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
7482  const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER);
7483 
7484  if (!(cfg = ast_config_load("queues.conf", config_flags))) {
7485  ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
7486  return -1;
7487  } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
7488  return 0;
7489  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
7490  ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format. Aborting.\n");
7491  return -1;
7492  }
7493 
7494  /* We've made it here, so it looks like we're doing operations on all queues. */
7495  ao2_lock(queues);
7496 
7497  /* Mark all queues as dead for the moment if we're reloading queues.
7498  * For clarity, we could just be reloading members, in which case we don't want to mess
7499  * with the other queue parameters at all*/
7500  if (queue_reload) {
7501  ao2_callback(queues, OBJ_NODATA, mark_dead_and_unfound, (char *) queuename);
7502  }
7503 
7504  if (member_reload) {
7506  }
7507 
7508  /* Chug through config file */
7509  cat = NULL;
7510  while ((cat = ast_category_browse(cfg, cat)) ) {
7511  if (!strcasecmp(cat, "general") && queue_reload) {
7513  continue;
7514  }
7515  if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename))
7516  reload_single_queue(cfg, mask, cat);
7517  }
7518 
7519  ast_config_destroy(cfg);
7520  /* Unref all the dead queues if we were reloading queues */
7521  if (queue_reload) {
7523  }
7524  ao2_unlock(queues);
7525  return 0;
7526 }
7527 
7528 /*! \brief Facilitates resetting statistics for a queue
7529  *
7530  * This function actually does not reset any statistics, but
7531  * rather finds a call_queue struct which corresponds to the
7532  * passed-in queue name and passes that structure to the
7533  * clear_queue function. If no queuename is passed in, then
7534  * all queues will have their statistics reset.
7535  *
7536  * \param queuename The name of the queue to reset the statistics
7537  * for. If this is NULL or zero-length, then this means to reset
7538  * the statistics for all queues
7539  * \retval void
7540  */
7541 static int clear_stats(const char *queuename)
7543  struct call_queue *q;
7544  struct ao2_iterator queue_iter;
7545 
7546  queue_iter = ao2_iterator_init(queues, 0);
7547  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
7548  ao2_lock(q);
7549  if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename))
7550  clear_queue(q);
7551  ao2_unlock(q);
7552  queue_t_unref(q, "Done with iterator");
7553  }
7554  ao2_iterator_destroy(&queue_iter);
7555  return 0;
7556 }
7557 
7558 /*! \brief The command center for all reload operations
7559  *
7560  * Whenever any piece of queue information is to be reloaded, this function
7561  * is called. It interprets the flags set in the mask parameter and acts
7562  * based on how they are set.
7563  *
7564  * \param reload True if we are reloading information, false if we are loading
7565  * information for the first time.
7566  * \param mask A bitmask which tells the handler what actions to take
7567  * \param queuename The name of the queue on which we wish to take action
7568  * \retval 0 All reloads were successful
7569  * \retval non-zero There was a failure
7570  */
7571 static int reload_handler(int reload, struct ast_flags *mask, const char *queuename)
7573  int res = 0;
7574 
7575  if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) {
7576  res |= reload_queue_rules(reload);
7577  }
7578  if (ast_test_flag(mask, QUEUE_RESET_STATS)) {
7579  res |= clear_stats(queuename);
7580  }
7582  res |= reload_queues(reload, mask, queuename);
7583  }
7584  return res;
7585 }
7586 
7587 /*! \brief direct ouput to manager or cli with proper terminator */
7588 static void do_print(struct mansession *s, int fd, const char *str)
7590  if (s)
7591  astman_append(s, "%s\r\n", str);
7592  else
7593  ast_cli(fd, "%s\n", str);
7594 }
7595 
7596 /*!
7597  * \brief Show queue(s) status and statistics
7598  *
7599  * List the queues strategy, calls processed, members logged in,
7600  * other queue statistics such as avg hold time.
7601 */
7602 static char *__queues_show(struct mansession *s, int fd, int argc, const char * const *argv)
7604  struct call_queue *q;
7605  struct ast_str *out = ast_str_alloca(240);
7606  int found = 0;
7607  time_t now = time(NULL);
7608  struct ao2_iterator queue_iter;
7609  struct ao2_iterator mem_iter;
7610 
7611  if (argc != 2 && argc != 3)
7612  return CLI_SHOWUSAGE;
7613 
7614  if (argc == 3) { /* specific queue */
7615  if ((q = load_realtime_queue(argv[2]))) {
7616  queue_t_unref(q, "Done with temporary pointer");
7617  }
7618  } else if (ast_check_realtime("queues")) {
7619  /* This block is to find any queues which are defined in realtime but
7620  * which have not yet been added to the in-core container
7621  */
7622  struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
7623  char *queuename;
7624  if (cfg) {
7625  for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) {
7626  if ((q = load_realtime_queue(queuename))) {
7627  queue_t_unref(q, "Done with temporary pointer");
7628  }
7629  }
7630  ast_config_destroy(cfg);
7631  }
7632  }
7633 
7634  ao2_lock(queues);
7636  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
7637  float sl;
7638  struct call_queue *realtime_queue = NULL;
7639 
7640  ao2_lock(q);
7641  /* This check is to make sure we don't print information for realtime
7642  * queues which have been deleted from realtime but which have not yet
7643  * been deleted from the in-core container. Only do this if we're not
7644  * looking for a specific queue.
7645  */
7646  if (argc < 3 && q->realtime) {
7647  realtime_queue = load_realtime_queue(q->name);
7648  if (!realtime_queue) {
7649  ao2_unlock(q);
7650  queue_t_unref(q, "Done with iterator");
7651  continue;
7652  }
7653  queue_t_unref(realtime_queue, "Queue is already in memory");
7654  }
7655 
7656  if (argc == 3 && strcasecmp(q->name, argv[2])) {
7657  ao2_unlock(q);
7658  queue_t_unref(q, "Done with iterator");
7659  continue;
7660  }
7661  found = 1;
7662 
7663  ast_str_set(&out, 0, "%s has %d calls (max ", q->name, q->count);
7664  if (q->maxlen)
7665  ast_str_append(&out, 0, "%d", q->maxlen);
7666  else
7667  ast_str_append(&out, 0, "unlimited");
7668  sl = 0;
7669  if (q->callscompleted > 0)
7670  sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
7671  ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime, %ds talktime), R:%d, W:%d, C:%d, A:%d, SL:%2.1f%% within %ds",
7672  int2strat(q->strategy), q->holdtime, q->talktime, q->ringlimit, q->weight,
7674  do_print(s, fd, ast_str_buffer(out));
7675  if (!ao2_container_count(q->members))
7676  do_print(s, fd, " No Members");
7677  else {
7678  struct member *mem;
7679 
7680  do_print(s, fd, " Members: ");
7681  mem_iter = ao2_iterator_init(q->members, 0);
7682  while ((mem = ao2_iterator_next(&mem_iter))) {
7683  ast_str_set(&out, 0, " %s", mem->membername);
7684  if (strcasecmp(mem->membername, mem->interface)) {
7685  ast_str_append(&out, 0, " (%s)", mem->interface);
7686  }
7687  if (mem->penalty)
7688  ast_str_append(&out, 0, " with penalty %d", mem->penalty);
7689  ast_str_append(&out, 0, "%s%s%s (%s)",
7690  mem->dynamic ? " (dynamic)" : "",
7691  mem->realtime ? " (realtime)" : "",
7692  mem->paused ? " (paused)" : "",
7693  ast_devstate2str(mem->status));
7694  if (mem->calls)
7695  ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)",
7696  mem->calls, (long) (time(NULL) - mem->lastcall));
7697  else
7698  ast_str_append(&out, 0, " has taken no calls yet");
7699  do_print(s, fd, ast_str_buffer(out));
7700  ao2_ref(mem, -1);
7701  }
7702  ao2_iterator_destroy(&mem_iter);
7703  }
7704  if (!q->head)
7705  do_print(s, fd, " No Callers");
7706  else {
7707  struct queue_ent *qe;
7708  int pos = 1;
7709 
7710  do_print(s, fd, " Callers: ");
7711  for (qe = q->head; qe; qe = qe->next) {
7712  ast_str_set(&out, 0, " %d. %s (wait: %ld:%2.2ld, prio: %d)",
7713  pos++, qe->chan->name, (long) (now - qe->start) / 60,
7714  (long) (now - qe->start) % 60, qe->prio);
7715  do_print(s, fd, ast_str_buffer(out));
7716  }
7717  }
7718  do_print(s, fd, ""); /* blank line between entries */
7719  ao2_unlock(q);
7720  queue_t_unref(q, "Done with iterator"); /* Unref the iterator's reference */
7721  }
7722  ao2_iterator_destroy(&queue_iter);
7723  ao2_unlock(queues);
7724  if (!found) {
7725  if (argc == 3)
7726  ast_str_set(&out, 0, "No such queue: %s.", argv[2]);
7727  else
7728  ast_str_set(&out, 0, "No queues.");
7729  do_print(s, fd, ast_str_buffer(out));
7730  }
7731  return CLI_SUCCESS;
7732 }
7733 
7734 /*!
7735  * \brief Check if a given word is in a space-delimited list
7736  *
7737  * \param list Space delimited list of words
7738  * \param word The word used to search the list
7739  *
7740  * \note This function will not return 1 if the word is at the very end of the
7741  * list (followed immediately by a \0, not a space) since it is used for
7742  * checking tab-completion and a word at the end is still being tab-completed.
7743  *
7744  * \return Returns 1 if the word is found
7745  * \return Returns 0 if the word is not found
7746 */
7747 static int word_in_list(const char *list, const char *word) {
7748  int list_len, word_len = strlen(word);
7749  const char *find, *end_find, *end_list;
7750 
7751  /* strip whitespace from front */
7752  while (isspace(*list)) {
7753  list++;
7754  }
7755 
7756  while ((find = strstr(list, word))) {
7757  /* beginning of find starts inside another word? */
7758  if (find != list && *(find - 1) != ' ') {
7759  list = find;
7760  /* strip word from front */
7761  while (!isspace(*list) && *list != '\0') {
7762  list++;
7763  }
7764  /* strip whitespace from front */
7765  while (isspace(*list)) {
7766  list++;
7767  }
7768  continue;
7769  }
7770 
7771  /* end of find ends inside another word or at very end of list? */
7772  list_len = strlen(list);
7773  end_find = find + word_len;
7774  end_list = list + list_len;
7775  if (end_find == end_list || *end_find != ' ') {
7776  list = find;
7777  /* strip word from front */
7778  while (!isspace(*list) && *list != '\0') {
7779  list++;
7780  }
7781  /* strip whitespace from front */
7782  while (isspace(*list)) {
7783  list++;
7784  }
7785  continue;
7786  }
7787 
7788  /* terminating conditions satisfied, word at beginning or separated by ' ' */
7789  return 1;
7790  }
7791 
7792  return 0;
7793 }
7794 
7795 /*!
7796  * \brief Check if a given word is in a space-delimited list
7797  *
7798  * \param line The line as typed not including the current word being completed
7799  * \param word The word currently being completed
7800  * \param pos The number of completed words in line
7801  * \param state The nth desired completion option
7802  * \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.
7803  *
7804  * \return Returns the queue tab-completion for the given word and state
7805 */
7806 static char *complete_queue(const char *line, const char *word, int pos, int state, ptrdiff_t word_list_offset)
7808  struct call_queue *q;
7809  char *ret = NULL;
7810  int which = 0;
7811  int wordlen = strlen(word);
7812  struct ao2_iterator queue_iter;
7813  const char *word_list = NULL;
7814 
7815  /* for certain commands, already completed items should be left out of
7816  * the list */
7817  if (word_list_offset && strlen(line) >= word_list_offset) {
7818  word_list = line + word_list_offset;
7819  }
7820 
7821  queue_iter = ao2_iterator_init(queues, 0);
7822  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
7823  if (!strncasecmp(word, q->name, wordlen) && ++which > state
7824  && (!word_list_offset || !word_in_list(word_list, q->name))) {
7825  ret = ast_strdup(q->name);
7826  queue_t_unref(q, "Done with iterator");
7827  break;
7828  }
7829  queue_t_unref(q, "Done with iterator");
7830  }
7831  ao2_iterator_destroy(&queue_iter);
7832 
7833  /* Pretend "rules" is at the end of the queues list in certain
7834  * circumstances since it is an alternate command that should be
7835  * tab-completable for "queue show" */
7836  if (!ret && which == state && !wordlen && !strncmp("queue show", line, 10)) {
7837  ret = ast_strdup("rules");
7838  }
7839 
7840  return ret;
7841 }
7842 
7843 static char *complete_queue_show(const char *line, const char *word, int pos, int state)
7845  if (pos == 2) {
7846  return complete_queue(line, word, pos, state, 0);
7847  }
7848  return NULL;
7849 }
7850 
7851 static char *queue_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
7853  switch ( cmd ) {
7854  case CLI_INIT:
7855  e->command = "queue show";
7856  e->usage =
7857  "Usage: queue show\n"
7858  " Provides summary information on a specified queue.\n";
7859  return NULL;
7860  case CLI_GENERATE:
7861  return complete_queue_show(a->line, a->word, a->pos, a->n);
7862  }
7863 
7864  return __queues_show(NULL, a->fd, a->argc, a->argv);
7865 }
7866 
7867 /*!\brief callback to display queues status in manager
7868  \addtogroup Group_AMI
7869  */
7870 static int manager_queues_show(struct mansession *s, const struct message *m)
7872  static const char * const a[] = { "queue", "show" };
7873 
7874  __queues_show(s, -1, 2, a);
7875  astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */
7876 
7877  return RESULT_SUCCESS;
7878 }
7879 
7880 static int manager_queue_rule_show(struct mansession *s, const struct message *m)
7882  const char *rule = astman_get_header(m, "Rule");
7883  const char *id = astman_get_header(m, "ActionID");
7884  struct rule_list *rl_iter;
7885  struct penalty_rule *pr_iter;
7886 
7887  astman_append(s, "Response: Success\r\n");
7888  if (!ast_strlen_zero(id)) {
7889  astman_append(s, "ActionID: %s\r\n", id);
7890  }
7891 
7893  AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
7894  if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) {
7895  astman_append(s, "RuleList: %s\r\n", rl_iter->name);
7896  AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
7897  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 );
7898  }
7899  if (!ast_strlen_zero(rule))
7900  break;
7901  }
7902  }
7904 
7905  /*
7906  * Two blank lines instead of one because the Response and
7907  * ActionID headers used to not be present.
7908  */
7909  astman_append(s, "\r\n\r\n");
7910 
7911  return RESULT_SUCCESS;
7912 }
7913 
7914 /*! \brief Summary of queue info via the AMI */
7915 static int manager_queues_summary(struct mansession *s, const struct message *m)
7917  time_t now;
7918  int qmemcount = 0;
7919  int qmemavail = 0;
7920  int qchancount = 0;
7921  int qlongestholdtime = 0;
7922  const char *id = astman_get_header(m, "ActionID");
7923  const char *queuefilter = astman_get_header(m, "Queue");
7924  char idText[256] = "";
7925  struct call_queue *q;
7926  struct queue_ent *qe;
7927  struct member *mem;
7928  struct ao2_iterator queue_iter;
7929  struct ao2_iterator mem_iter;
7930 
7931  astman_send_ack(s, m, "Queue summary will follow");
7932  time(&now);
7933  if (!ast_strlen_zero(id))
7934  snprintf(idText, 256, "ActionID: %s\r\n", id);
7935  queue_iter = ao2_iterator_init(queues, 0);
7936  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
7937  ao2_lock(q);
7938 
7939  /* List queue properties */
7940  if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
7941  /* Reset the necessary local variables if no queuefilter is set*/
7942  qmemcount = 0;
7943  qmemavail = 0;
7944  qchancount = 0;
7945  qlongestholdtime = 0;
7946 
7947  /* List Queue Members */
7948  mem_iter = ao2_iterator_init(q->members, 0);
7949  while ((mem = ao2_iterator_next(&mem_iter))) {
7950  if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) {
7951  ++qmemcount;
7952  if (member_status_available(mem->status) && !mem->paused) {
7953  ++qmemavail;
7954  }
7955  }
7956  ao2_ref(mem, -1);
7957  }
7958  ao2_iterator_destroy(&mem_iter);
7959  for (qe = q->head; qe; qe = qe->next) {
7960  if ((now - qe->start) > qlongestholdtime) {
7961  qlongestholdtime = now - qe->start;
7962  }
7963  ++qchancount;
7964  }
7965  astman_append(s, "Event: QueueSummary\r\n"
7966  "Queue: %s\r\n"
7967  "LoggedIn: %d\r\n"
7968  "Available: %d\r\n"
7969  "Callers: %d\r\n"
7970  "HoldTime: %d\r\n"
7971  "TalkTime: %d\r\n"
7972  "LongestHoldTime: %d\r\n"
7973  "%s"
7974  "\r\n",
7975  q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText);
7976  }
7977  ao2_unlock(q);
7978  queue_t_unref(q, "Done with iterator");
7979  }
7980  ao2_iterator_destroy(&queue_iter);
7981  astman_append(s,
7982  "Event: QueueSummaryComplete\r\n"
7983  "%s"
7984  "\r\n", idText);
7985 
7986  return RESULT_SUCCESS;
7987 }
7988 
7989 /*! \brief Queue status info via AMI */
7990 static int manager_queues_status(struct mansession *s, const struct message *m)
7992  time_t now;
7993  int pos;
7994  const char *id = astman_get_header(m,"ActionID");
7995  const char *queuefilter = astman_get_header(m,"Queue");
7996  const char *memberfilter = astman_get_header(m,"Member");
7997  char idText[256] = "";
7998  struct call_queue *q;
7999  struct queue_ent *qe;
8000  float sl = 0;
8001  struct member *mem;
8002  struct ao2_iterator queue_iter;
8003  struct ao2_iterator mem_iter;
8004 
8005  astman_send_ack(s, m, "Queue status will follow");
8006  time(&now);
8007  if (!ast_strlen_zero(id))
8008  snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
8009 
8010  queue_iter = ao2_iterator_init(queues, 0);
8011  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
8012  ao2_lock(q);
8013 
8014  /* List queue properties */
8015  if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
8016  sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0);
8017  astman_append(s, "Event: QueueParams\r\n"
8018  "Queue: %s\r\n"
8019  "Max: %d\r\n"
8020  "Strategy: %s\r\n"
8021  "Calls: %d\r\n"
8022  "Holdtime: %d\r\n"
8023  "TalkTime: %d\r\n"
8024  "Completed: %d\r\n"
8025  "Abandoned: %d\r\n"
8026  "ServiceLevel: %d\r\n"
8027  "ServicelevelPerf: %2.1f\r\n"
8028  "RingLimit: %d\r\n"
8029  "Weight: %d\r\n"
8030  "%s"
8031  "\r\n",
8032  q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted,
8033  q->callsabandoned, q->servicelevel, sl, q->ringlimit, q->weight, idText);
8034  /* List Queue Members */
8035  mem_iter = ao2_iterator_init(q->members, 0);
8036  while ((mem = ao2_iterator_next(&mem_iter))) {
8037  if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) {
8038  astman_append(s, "Event: QueueMember\r\n"
8039  "Queue: %s\r\n"
8040  "Name: %s\r\n"
8041  "Location: %s\r\n"
8042  "Membership: %s\r\n"
8043  "Penalty: %d\r\n"
8044  "CallsTaken: %d\r\n"
8045  "LastCall: %d\r\n"
8046  "Status: %d\r\n"
8047  "Paused: %d\r\n"
8048  "%s"
8049  "\r\n",
8050  q->name, mem->membername, mem->interface, mem->dynamic ? "dynamic" : "static",
8051  mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText);
8052  }
8053  ao2_ref(mem, -1);
8054  }
8055  ao2_iterator_destroy(&mem_iter);
8056  /* List Queue Entries */
8057  pos = 1;
8058  for (qe = q->head; qe; qe = qe->next) {
8059  astman_append(s, "Event: QueueEntry\r\n"
8060  "Queue: %s\r\n"
8061  "Position: %d\r\n"
8062  "Channel: %s\r\n"
8063  "Uniqueid: %s\r\n"
8064  "CallerIDNum: %s\r\n"
8065  "CallerIDName: %s\r\n"
8066  "ConnectedLineNum: %s\r\n"
8067  "ConnectedLineName: %s\r\n"
8068  "Wait: %ld\r\n"
8069  "%s"
8070  "\r\n",
8071  q->name, pos++, qe->chan->name, qe->chan->uniqueid,
8072  S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"),
8073  S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"),
8074  S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"),
8075  S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"),
8076  (long) (now - qe->start), idText);
8077  }
8078  }
8079  ao2_unlock(q);
8080  queue_t_unref(q, "Done with iterator");
8081  }
8082  ao2_iterator_destroy(&queue_iter);
8083 
8084  astman_append(s,
8085  "Event: QueueStatusComplete\r\n"
8086  "%s"
8087  "\r\n",idText);
8088 
8089  return RESULT_SUCCESS;
8090 }
8091 
8092 static int manager_add_queue_member(struct mansession *s, const struct message *m)
8094  const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface;
8095  int paused, penalty = 0;
8096 
8097  queuename = astman_get_header(m, "Queue");
8098  interface = astman_get_header(m, "Interface");
8099  penalty_s = astman_get_header(m, "Penalty");
8100  paused_s = astman_get_header(m, "Paused");
8101  membername = astman_get_header(m, "MemberName");
8102  state_interface = astman_get_header(m, "StateInterface");
8103 
8104  if (ast_strlen_zero(queuename)) {
8105  astman_send_error(s, m, "'Queue' not specified.");
8106  return 0;
8107  }
8108 
8109  if (ast_strlen_zero(interface)) {
8110  astman_send_error(s, m, "'Interface' not specified.");
8111  return 0;
8112  }
8113 
8114  if (ast_strlen_zero(penalty_s))
8115  penalty = 0;
8116  else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0)
8117  penalty = 0;
8118 
8119  if (ast_strlen_zero(paused_s))
8120  paused = 0;
8121  else
8122  paused = abs(ast_true(paused_s));
8123 
8124  switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) {
8125  case RES_OKAY:
8126  ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
8127  astman_send_ack(s, m, "Added interface to queue");
8128  break;
8129  case RES_EXISTS:
8130  astman_send_error(s, m, "Unable to add interface: Already there");
8131  break;
8132  case RES_NOSUCHQUEUE:
8133  astman_send_error(s, m, "Unable to add interface to queue: No such queue");
8134  break;
8135  case RES_OUTOFMEMORY:
8136  astman_send_error(s, m, "Out of memory");
8137  break;
8138  }
8139 
8140  return 0;
8141 }
8142 
8143 static int manager_remove_queue_member(struct mansession *s, const struct message *m)
8145  const char *queuename, *interface;
8146 
8147  queuename = astman_get_header(m, "Queue");
8148  interface = astman_get_header(m, "Interface");
8149 
8150  if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
8151  astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
8152  return 0;
8153  }
8154 
8155  switch (remove_from_queue(queuename, interface)) {
8156  case RES_OKAY:
8157  ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
8158  astman_send_ack(s, m, "Removed interface from queue");
8159  break;
8160  case RES_EXISTS:
8161  astman_send_error(s, m, "Unable to remove interface: Not there");
8162  break;
8163  case RES_NOSUCHQUEUE:
8164  astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
8165  break;
8166  case RES_OUTOFMEMORY:
8167  astman_send_error(s, m, "Out of memory");
8168  break;
8169  case RES_NOT_DYNAMIC:
8170  astman_send_error(s, m, "Member not dynamic");
8171  break;
8172  }
8173 
8174  return 0;
8175 }
8176 
8177 static int manager_pause_queue_member(struct mansession *s, const struct message *m)
8179  const char *queuename, *interface, *paused_s, *reason;
8180  int paused;
8181 
8182  interface = astman_get_header(m, "Interface");
8183  paused_s = astman_get_header(m, "Paused");
8184  queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */
8185  reason = astman_get_header(m, "Reason"); /* Optional - Only used for logging purposes */
8186 
8187  if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
8188  astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
8189  return 0;
8190  }
8191 
8192  paused = abs(ast_true(paused_s));
8193 
8194  if (set_member_paused(queuename, interface, reason, paused))
8195  astman_send_error(s, m, "Interface not found");
8196  else
8197  astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
8198  return 0;
8199 }
8200 
8201 static int manager_queue_log_custom(struct mansession *s, const struct message *m)
8203  const char *queuename, *event, *message, *interface, *uniqueid;
8204 
8205  queuename = astman_get_header(m, "Queue");
8206  uniqueid = astman_get_header(m, "UniqueId");
8207  interface = astman_get_header(m, "Interface");
8208  event = astman_get_header(m, "Event");
8209  message = astman_get_header(m, "Message");
8210 
8211  if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) {
8212  astman_send_error(s, m, "Need 'Queue' and 'Event' parameters.");
8213  return 0;
8214  }
8215 
8216  ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message);
8217  astman_send_ack(s, m, "Event added successfully");
8218 
8219  return 0;
8220 }
8221 
8222 static int manager_queue_reload(struct mansession *s, const struct message *m)
8224  struct ast_flags mask = {0,};
8225  const char *queuename = NULL;
8226  int header_found = 0;
8227 
8228  queuename = astman_get_header(m, "Queue");
8229  if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) {
8231  header_found = 1;
8232  }
8233  if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) {
8235  header_found = 1;
8236  }
8237  if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) {
8239  header_found = 1;
8240  }
8241 
8242  if (!header_found) {
8243  ast_set_flag(&mask, AST_FLAGS_ALL);
8244  }
8245 
8246  if (!reload_handler(1, &mask, queuename)) {
8247  astman_send_ack(s, m, "Queue reloaded successfully");
8248  } else {
8249  astman_send_error(s, m, "Error encountered while reloading queue");
8250  }
8251  return 0;
8252 }
8253 
8254 static int manager_queue_reset(struct mansession *s, const struct message *m)
8256  const char *queuename = NULL;
8257  struct ast_flags mask = {QUEUE_RESET_STATS,};
8258 
8259  queuename = astman_get_header(m, "Queue");
8260 
8261  if (!reload_handler(1, &mask, queuename)) {
8262  astman_send_ack(s, m, "Queue stats reset successfully");
8263  } else {
8264  astman_send_error(s, m, "Error encountered while resetting queue stats");
8265  }
8266  return 0;
8267 }
8268 
8269 static char *complete_queue_add_member(const char *line, const char *word, int pos, int state)
8271  /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
8272  switch (pos) {
8273  case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
8274  return NULL;
8275  case 4: /* only one possible match, "to" */
8276  return state == 0 ? ast_strdup("to") : NULL;
8277  case 5: /* <queue> */
8278  return complete_queue(line, word, pos, state, 0);
8279  case 6: /* only one possible match, "penalty" */
8280  return state == 0 ? ast_strdup("penalty") : NULL;
8281  case 7:
8282  if (state < 100) { /* 0-99 */
8283  char *num;
8284  if ((num = ast_malloc(3))) {
8285  sprintf(num, "%d", state);
8286  }
8287  return num;
8288  } else {
8289  return NULL;
8290  }
8291  case 8: /* only one possible match, "as" */
8292  return state == 0 ? ast_strdup("as") : NULL;
8293  case 9: /* Don't attempt to complete name of member (infinite possibilities) */
8294  return NULL;
8295  default:
8296  return NULL;
8297  }
8298 }
8299 
8300 static int manager_queue_member_penalty(struct mansession *s, const struct message *m)
8302  const char *queuename, *interface, *penalty_s;
8303  int penalty;
8304 
8305  interface = astman_get_header(m, "Interface");
8306  penalty_s = astman_get_header(m, "Penalty");
8307  /* Optional - if not supplied, set the penalty value for the given Interface in all queues */
8308  queuename = astman_get_header(m, "Queue");
8309 
8310  if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) {
8311  astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters.");
8312  return 0;
8313  }
8314 
8315  penalty = atoi(penalty_s);
8316 
8317  if (set_member_penalty((char *)queuename, (char *)interface, penalty))
8318  astman_send_error(s, m, "Invalid interface, queuename or penalty");
8319  else
8320  astman_send_ack(s, m, "Interface penalty set successfully");
8321 
8322  return 0;
8323 }
8324 
8325 static char *handle_queue_add_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
8327  const char *queuename, *interface, *membername = NULL, *state_interface = NULL;
8328  int penalty;
8329 
8330  switch ( cmd ) {
8331  case CLI_INIT:
8332  e->command = "queue add member";
8333  e->usage =
8334  "Usage: queue add member <dial string> to <queue> [[[penalty <penalty>] as <membername>] state_interface <interface>]\n"
8335  " 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";
8336  return NULL;
8337  case CLI_GENERATE:
8338  return complete_queue_add_member(a->line, a->word, a->pos, a->n);
8339  }
8340 
8341  if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12)) {
8342  return CLI_SHOWUSAGE;
8343  } else if (strcmp(a->argv[4], "to")) {
8344  return CLI_SHOWUSAGE;
8345  } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) {
8346  return CLI_SHOWUSAGE;
8347  } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) {
8348  return CLI_SHOWUSAGE;
8349  } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) {
8350  return CLI_SHOWUSAGE;
8351  }
8352 
8353  queuename = a->argv[5];
8354  interface = a->argv[3];
8355  if (a->argc >= 8) {
8356  if (sscanf(a->argv[7], "%30d", &penalty) == 1) {
8357  if (penalty < 0) {
8358  ast_cli(a->fd, "Penalty must be >= 0\n");
8359  penalty = 0;
8360  }
8361  } else {
8362  ast_cli(a->fd, "Penalty must be an integer >= 0\n");
8363  penalty = 0;
8364  }
8365  } else {
8366  penalty = 0;
8367  }
8368 
8369  if (a->argc >= 10) {
8370  membername = a->argv[9];
8371  }
8372 
8373  if (a->argc >= 12) {
8374  state_interface = a->argv[11];
8375  }
8376 
8377  switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) {
8378  case RES_OKAY:
8379  ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
8380  ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
8381  return CLI_SUCCESS;
8382  case RES_EXISTS:
8383  ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
8384  return CLI_FAILURE;
8385  case RES_NOSUCHQUEUE:
8386  ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
8387  return CLI_FAILURE;
8388  case RES_OUTOFMEMORY:
8389  ast_cli(a->fd, "Out of memory\n");
8390  return CLI_FAILURE;
8391  case RES_NOT_DYNAMIC:
8392  ast_cli(a->fd, "Member not dynamic\n");
8393  return CLI_FAILURE;
8394  default:
8395  return CLI_FAILURE;
8396  }
8397 }
8398 
8399 static char *complete_queue_remove_member(const char *line, const char *word, int pos, int state)
8401  int which = 0;
8402  struct call_queue *q;
8403  struct member *m;
8404  struct ao2_iterator queue_iter;
8405  struct ao2_iterator mem_iter;
8406  int wordlen = strlen(word);
8407 
8408  /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
8409  if (pos > 5 || pos < 3)
8410  return NULL;
8411  if (pos == 4) /* only one possible match, 'from' */
8412  return (state == 0 ? ast_strdup("from") : NULL);
8413 
8414  if (pos == 5) { /* No need to duplicate code */
8415  return complete_queue(line, word, pos, state, 0);
8416  }
8417 
8418  /* here is the case for 3, <member> */
8419  queue_iter = ao2_iterator_init(queues, 0);
8420  while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
8421  ao2_lock(q);
8422  mem_iter = ao2_iterator_init(q->members, 0);
8423  while ((m = ao2_iterator_next(&mem_iter))) {
8424  if (!strncasecmp(word, m->membername, wordlen) && ++which > state) {
8425  char *tmp;
8426  tmp = ast_strdup(m->interface);
8427  ao2_ref(m, -1);
8428  ao2_iterator_destroy(&mem_iter);
8429  ao2_unlock(q);
8430  queue_t_unref(q, "Done with iterator, returning interface name");
8431  ao2_iterator_destroy(&queue_iter);
8432  return tmp;
8433  }
8434  ao2_ref(m, -1);
8435  }
8436  ao2_iterator_destroy(&mem_iter);
8437  ao2_unlock(q);
8438  queue_t_unref(q, "Done with iterator");
8439  }
8440  ao2_iterator_destroy(&queue_iter);
8441 
8442  return NULL;
8443 }
8444 
8445 static char *handle_queue_remove_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
8447  const char *queuename, *interface;
8448 
8449  switch (cmd) {
8450  case CLI_INIT:
8451  e->command = "queue remove member";
8452  e->usage =
8453  "Usage: queue remove member <channel> from <queue>\n"
8454  " Remove a specific channel from a queue.\n";
8455  return NULL;
8456  case CLI_GENERATE:
8457  return complete_queue_remove_member(a->line, a->word, a->pos, a->n);
8458  }
8459 
8460  if (a->argc != 6) {
8461  return CLI_SHOWUSAGE;
8462  } else if (strcmp(a->argv[4], "from")) {
8463  return CLI_SHOWUSAGE;
8464  }
8465 
8466  queuename = a->argv[5];
8467  interface = a->argv[3];
8468 
8469  switch (remove_from_queue(queuename, interface)) {
8470  case RES_OKAY:
8471  ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
8472  ast_cli(a->fd, "Removed interface '%s' from queue '%s'\n", interface, queuename);
8473  return CLI_SUCCESS;
8474  case RES_EXISTS:
8475  ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
8476  return CLI_FAILURE;
8477  case RES_NOSUCHQUEUE:
8478  ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
8479  return CLI_FAILURE;
8480  case RES_OUTOFMEMORY:
8481  ast_cli(a->fd, "Out of memory\n");
8482  return CLI_FAILURE;
8483  case RES_NOT_DYNAMIC:
8484  ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Member is not dynamic\n", interface, queuename);
8485  return CLI_FAILURE;
8486  default:
8487  return CLI_FAILURE;
8488  }
8489 }
8490 
8491 static char *complete_queue_pause_member(const char *line, const char *word, int pos, int state)
8493  /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */
8494  switch (pos) {
8495  case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
8496  return NULL;
8497  case 4: /* only one possible match, "queue" */
8498  return state == 0 ? ast_strdup("queue") : NULL;
8499  case 5: /* <queue> */
8500  return complete_queue(line, word, pos, state, 0);
8501  case 6: /* "reason" */
8502  return state == 0 ? ast_strdup("reason") : NULL;
8503  case 7: /* Can't autocomplete a reason, since it's 100% customizeable */
8504  return NULL;
8505  default:
8506  return NULL;
8507  }
8508 }
8509 
8510 static char *handle_queue_pause_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
8512  const char *queuename, *interface, *reason;
8513  int paused;
8514 
8515  switch (cmd) {
8516  case CLI_INIT:
8517  e->command = "queue {pause|unpause} member";
8518  e->usage =
8519  "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n"
8520  " Pause or unpause a queue member. Not specifying a particular queue\n"
8521  " will pause or unpause a member across all queues to which the member\n"
8522  " belongs.\n";
8523  return NULL;
8524  case CLI_GENERATE:
8525  return complete_queue_pause_member(a->line, a-> word, a->pos, a->n);
8526  }
8527 
8528  if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) {
8529  return CLI_SHOWUSAGE;
8530  } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) {
8531  return CLI_SHOWUSAGE;
8532  } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) {
8533  return CLI_SHOWUSAGE;
8534  }
8535 
8536 
8537  interface = a->argv[3];
8538  queuename = a->argc >= 6 ? a->argv[5] : NULL;
8539  reason = a->argc == 8 ? a->argv[7] : NULL;
8540  paused = !strcasecmp(a->argv[1], "pause");
8541 
8542  if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) {
8543  ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface);
8544  if (!ast_strlen_zero(queuename))
8545  ast_cli(a->fd, " in queue '%s'", queuename);
8546  if (!ast_strlen_zero(reason))
8547  ast_cli(a->fd, " for reason '%s'", reason);
8548  ast_cli(a->fd, "\n");
8549  return CLI_SUCCESS;
8550  } else {
8551  ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface);
8552  if (!ast_strlen_zero(queuename))
8553  ast_cli(a->fd, " in queue '%s'", queuename);
8554  if (!ast_strlen_zero(reason))
8555  ast_cli(a->fd, " for reason '%s'", reason);
8556  ast_cli(a->fd, "\n");
8557  return CLI_FAILURE;
8558  }
8559 }
8560 
8561 static char *complete_queue_set_member_penalty(const char *line, const char *word, int pos, int state)
8563  /* 0 - queue; 1 - set; 2 - penalty; 3 - <penalty>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/
8564  switch (pos) {
8565  case 4:
8566  if (state == 0) {
8567  return ast_strdup("on");
8568  } else {
8569  return NULL;
8570  }
8571  case 6:
8572  if (state == 0) {
8573  return ast_strdup("in");
8574  } else {
8575  return NULL;
8576  }
8577  case 7:
8578  return complete_queue(line, word, pos, state, 0);
8579  default:
8580  return NULL;
8581  }
8582 }
8583 
8584 static char *handle_queue_set_member_penalty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
8586  const char *queuename = NULL, *interface;
8587  int penalty = 0;
8588 
8589  switch (cmd) {
8590  case CLI_INIT:
8591  e->command = "queue set penalty";
8592  e->usage =
8593  "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n"
8594  " Set a member's penalty in the queue specified. If no queue is specified\n"
8595  " then that interface's penalty is set in all queues to which that interface is a member\n";
8596  return NULL;
8597  case CLI_GENERATE:
8598  return complete_queue_set_member_penalty(a->line, a->word, a->pos, a->n);
8599  }
8600 
8601  if (a->argc != 6 && a->argc != 8) {
8602  return CLI_SHOWUSAGE;
8603  } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
8604  return CLI_SHOWUSAGE;
8605  }
8606 
8607  if (a->argc == 8)
8608  queuename = a->argv[7];
8609  interface = a->argv[5];
8610  penalty = atoi(a->argv[3]);
8611 
8612  switch (set_member_penalty(queuename, interface, penalty)) {
8613  case RESULT_SUCCESS:
8614  ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename);
8615  return CLI_SUCCESS;
8616  case RESULT_FAILURE:
8617  ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename);
8618  return CLI_FAILURE;
8619  default:
8620  return CLI_FAILURE;
8621  }
8622 }
8623 
8624 static char *complete_queue_rule_show(const char *line, const char *word, int pos, int state)
8626  int which = 0;
8627  struct rule_list *rl_iter;
8628  int wordlen = strlen(word);
8629  char *ret = NULL;
8630  if (pos != 3) /* Wha? */ {
8631  return NULL;
8632  }
8633 
8635  AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
8636  if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) {
8637  ret = ast_strdup(rl_iter->name);
8638  break;
8639  }
8640  }
8642 
8643  return ret;
8644 }
8645 
8646 static char *handle_queue_rule_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
8648  const char *rule;
8649  struct rule_list *rl_iter;
8650  struct penalty_rule *pr_iter;
8651  switch (cmd) {
8652  case CLI_INIT:
8653  e->command = "queue show rules";
8654  e->usage =
8655  "Usage: queue show rules [rulename]\n"
8656  " Show the list of rules associated with rulename. If no\n"
8657  " rulename is specified, list all rules defined in queuerules.conf\n";
8658  return NULL;
8659  case CLI_GENERATE:
8660  return complete_queue_rule_show(a->line, a->word, a->pos, a->n);
8661  }
8662 
8663  if (a->argc != 3 && a->argc != 4)
8664  return CLI_SHOWUSAGE;
8665 
8666  rule = a->argc == 4 ? a->argv[3] : "";
8668  AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
8669  if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) {
8670  ast_cli(a->fd, "Rule: %s\n", rl_iter->name);
8671  AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
8672  ast_cli(a->fd, "\tAfter %d seconds, adjust QUEUE_MAX_PENALTY %s %d and adjust QUEUE_MIN_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);
8673  }
8674  }
8675  }
8677  return CLI_SUCCESS;
8678 }
8679 
8680 static char *handle_queue_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
8682  struct ast_flags mask = {QUEUE_RESET_STATS,};
8683  int i;
8684 
8685  switch (cmd) {
8686  case CLI_INIT:
8687  e->command = "queue reset stats";
8688  e->usage =
8689  "Usage: queue reset stats [<queuenames>]\n"
8690  "\n"
8691  "Issuing this command will reset statistics for\n"
8692  "<queuenames>, or for all queues if no queue is\n"
8693  "specified.\n";
8694  return NULL;
8695  case CLI_GENERATE:
8696  if (a->pos >= 3) {
8697  return complete_queue(a->line, a->word, a->pos, a->n, 17);
8698  } else {
8699  return NULL;
8700  }
8701  }
8702 
8703  if (a->argc < 3) {
8704  return CLI_SHOWUSAGE;
8705  }
8706 
8707  if (a->argc == 3) {
8708  reload_handler(1, &mask, NULL);
8709  return CLI_SUCCESS;
8710  }
8711 
8712  for (i = 3; i < a->argc; ++i) {
8713  reload_handler(1, &mask, a->argv[i]);
8714  }
8715 
8716  return CLI_SUCCESS;
8717 }
8718 
8719 static char *handle_queue_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
8721  struct ast_flags mask = {0,};
8722  int i;
8723 
8724  switch (cmd) {
8725  case CLI_INIT:
8726  e->command = "queue reload {parameters|members|rules|all}";
8727  e->usage =
8728  "Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n"
8729  "Reload queues. If <queuenames> are specified, only reload information pertaining\n"
8730  "to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n"
8731  "specified in order to know what information to reload. Below is an explanation\n"
8732  "of each of these qualifiers.\n"
8733  "\n"
8734  "\t'members' - reload queue members from queues.conf\n"
8735  "\t'parameters' - reload all queue options except for queue members\n"
8736  "\t'rules' - reload the queuerules.conf file\n"
8737  "\t'all' - reload queue rules, parameters, and members\n"
8738  "\n"
8739  "Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n"
8740  "Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n"
8741  "one queue is specified when using this command, reloading queue rules may cause\n"
8742  "other queues to be affected\n";
8743  return NULL;
8744  case CLI_GENERATE:
8745  if (a->pos >= 3) {
8746  /* find the point at which the list of queue names starts */
8747  const char *command_end = a->line + strlen("queue reload ");
8748  command_end = strchr(command_end, ' ');
8749  if (!command_end) {
8750  command_end = a->line + strlen(a->line);
8751  }
8752  return complete_queue(a->line, a->word, a->pos, a->n, command_end - a->line);
8753  } else {
8754  return NULL;
8755  }
8756  }
8757 
8758  if (a->argc < 3)
8759  return CLI_SHOWUSAGE;
8760 
8761  if (!strcasecmp(a->argv[2], "rules")) {
8763  } else if (!strcasecmp(a->argv[2], "members")) {
8765  } else if (!strcasecmp(a->argv[2], "parameters")) {
8767  } else if (!strcasecmp(a->argv[2], "all")) {
8768  ast_set_flag(&mask, AST_FLAGS_ALL);
8769  }
8770 
8771  if (a->argc == 3) {
8772  reload_handler(1, &mask, NULL);
8773  return CLI_SUCCESS;
8774  }
8775 
8776  for (i = 3; i < a->argc; ++i) {
8777  reload_handler(1, &mask, a->argv[i]);
8778  }
8779 
8780  return CLI_SUCCESS;
8781 }
8782 
8783 static const char qpm_cmd_usage[] =
8784 "Usage: queue pause member <channel> in <queue> reason <reason>\n";
8785 
8786 static const char qum_cmd_usage[] =
8787 "Usage: queue unpause member <channel> in <queue> reason <reason>\n";
8788 
8789 static const char qsmp_cmd_usage[] =
8790 "Usage: queue set member penalty <channel> from <queue> <penalty>\n";
8791 
8792 static struct ast_cli_entry cli_queue[] = {
8793  AST_CLI_DEFINE(queue_show, "Show status of a specified queue"),
8794  AST_CLI_DEFINE(handle_queue_rule_show, "Show the rules defined in queuerules.conf"),
8795  AST_CLI_DEFINE(handle_queue_add_member, "Add a channel to a specified queue"),
8796  AST_CLI_DEFINE(handle_queue_remove_member, "Removes a channel from a specified queue"),
8797  AST_CLI_DEFINE(handle_queue_pause_member, "Pause or unpause a queue member"),
8798  AST_CLI_DEFINE(handle_queue_set_member_penalty, "Set penalty for a channel of a specified queue"),
8799  AST_CLI_DEFINE(handle_queue_reload, "Reload queues, members, queue rules, or parameters"),
8800  AST_CLI_DEFINE(handle_queue_reset, "Reset statistics for a queue"),
8801 };
8802 
8803 /* struct call_queue astdata mapping. */
8804 #define DATA_EXPORT_CALL_QUEUE(MEMBER) \
8805  MEMBER(call_queue, name, AST_DATA_STRING) \
8806  MEMBER(call_queue, moh, AST_DATA_STRING) \
8807  MEMBER(call_queue, announce, AST_DATA_STRING) \
8808  MEMBER(call_queue, context, AST_DATA_STRING) \
8809  MEMBER(call_queue, membermacro, AST_DATA_STRING) \
8810  MEMBER(call_queue, membergosub, AST_DATA_STRING) \
8811  MEMBER(call_queue, defaultrule, AST_DATA_STRING) \
8812  MEMBER(call_queue, sound_next, AST_DATA_STRING) \
8813  MEMBER(call_queue, sound_thereare, AST_DATA_STRING) \
8814  MEMBER(call_queue, sound_calls, AST_DATA_STRING) \
8815  MEMBER(call_queue, queue_quantity1, AST_DATA_STRING) \
8816  MEMBER(call_queue, queue_quantity2, AST_DATA_STRING) \
8817  MEMBER(call_queue, sound_holdtime, AST_DATA_STRING) \
8818  MEMBER(call_queue, sound_minutes, AST_DATA_STRING) \
8819  MEMBER(call_queue, sound_minute, AST_DATA_STRING) \
8820  MEMBER(call_queue, sound_seconds, AST_DATA_STRING) \
8821  MEMBER(call_queue, sound_thanks, AST_DATA_STRING) \
8822  MEMBER(call_queue, sound_callerannounce, AST_DATA_STRING) \
8823  MEMBER(call_queue, sound_reporthold, AST_DATA_STRING) \
8824  MEMBER(call_queue, dead, AST_DATA_BOOLEAN) \
8825  MEMBER(call_queue, eventwhencalled, AST_DATA_BOOLEAN) \
8826  MEMBER(call_queue, ringinuse, AST_DATA_BOOLEAN) \
8827  MEMBER(call_queue, announce_to_first_user, AST_DATA_BOOLEAN) \
8828  MEMBER(call_queue, setinterfacevar, AST_DATA_BOOLEAN) \
8829  MEMBER(call_queue, setqueuevar, AST_DATA_BOOLEAN) \
8830  MEMBER(call_queue, setqueueentryvar, AST_DATA_BOOLEAN) \
8831  MEMBER(call_queue, reportholdtime, AST_DATA_BOOLEAN) \
8832  MEMBER(call_queue, wrapped, AST_DATA_BOOLEAN) \
8833  MEMBER(call_queue, timeoutrestart, AST_DATA_BOOLEAN) \
8834  MEMBER(call_queue, announceholdtime, AST_DATA_INTEGER) \
8835  MEMBER(call_queue, maskmemberstatus, AST_DATA_BOOLEAN) \
8836  MEMBER(call_queue, realtime, AST_DATA_BOOLEAN) \
8837  MEMBER(call_queue, found, AST_DATA_BOOLEAN) \
8838  MEMBER(call_queue, announcepositionlimit, AST_DATA_INTEGER) \
8839  MEMBER(call_queue, announcefrequency, AST_DATA_SECONDS) \
8840  MEMBER(call_queue, minannouncefrequency, AST_DATA_SECONDS) \
8841  MEMBER(call_queue, periodicannouncefrequency, AST_DATA_SECONDS) \
8842  MEMBER(call_queue, numperiodicannounce, AST_DATA_INTEGER) \
8843  MEMBER(call_queue, randomperiodicannounce, AST_DATA_INTEGER) \
8844  MEMBER(call_queue, roundingseconds, AST_DATA_SECONDS) \
8845  MEMBER(call_queue, holdtime, AST_DATA_SECONDS) \
8846  MEMBER(call_queue, talktime, AST_DATA_SECONDS) \
8847  MEMBER(call_queue, callscompleted, AST_DATA_INTEGER) \
8848  MEMBER(call_queue, callsabandoned, AST_DATA_INTEGER) \
8849  MEMBER(call_queue, servicelevel, AST_DATA_INTEGER) \
8850  MEMBER(call_queue, callscompletedinsl, AST_DATA_INTEGER) \
8851  MEMBER(call_queue, monfmt, AST_DATA_STRING) \
8852  MEMBER(call_queue, montype, AST_DATA_INTEGER) \
8853  MEMBER(call_queue, count, AST_DATA_INTEGER) \
8854  MEMBER(call_queue, maxlen, AST_DATA_INTEGER) \
8855  MEMBER(call_queue, wrapuptime, AST_DATA_SECONDS) \
8856  MEMBER(call_queue, retry, AST_DATA_SECONDS) \
8857  MEMBER(call_queue, timeout, AST_DATA_SECONDS) \
8858  MEMBER(call_queue, weight, AST_DATA_INTEGER) \
8859  MEMBER(call_queue, autopause, AST_DATA_INTEGER) \
8860  MEMBER(call_queue, timeoutpriority, AST_DATA_INTEGER) \
8861  MEMBER(call_queue, rrpos, AST_DATA_INTEGER) \
8862  MEMBER(call_queue, memberdelay, AST_DATA_INTEGER) \
8863  MEMBER(call_queue, autofill, AST_DATA_INTEGER) \
8864  MEMBER(call_queue, members, AST_DATA_CONTAINER)
8865 
8867 
8868 /* struct member astdata mapping. */
8869 #define DATA_EXPORT_MEMBER(MEMBER) \
8870  MEMBER(member, interface, AST_DATA_STRING) \
8871  MEMBER(member, state_interface, AST_DATA_STRING) \
8872  MEMBER(member, membername, AST_DATA_STRING) \
8873  MEMBER(member, penalty, AST_DATA_INTEGER) \
8874  MEMBER(member, calls, AST_DATA_INTEGER) \
8875  MEMBER(member, dynamic, AST_DATA_INTEGER) \
8876  MEMBER(member, realtime, AST_DATA_INTEGER) \
8877  MEMBER(member, status, AST_DATA_INTEGER) \
8878  MEMBER(member, paused, AST_DATA_BOOLEAN) \
8879  MEMBER(member, rt_uniqueid, AST_DATA_STRING)
8880 
8882 
8883 #define DATA_EXPORT_QUEUE_ENT(MEMBER) \
8884  MEMBER(queue_ent, moh, AST_DATA_STRING) \
8885  MEMBER(queue_ent, announce, AST_DATA_STRING) \
8886  MEMBER(queue_ent, context, AST_DATA_STRING) \
8887  MEMBER(queue_ent, digits, AST_DATA_STRING) \
8888  MEMBER(queue_ent, valid_digits, AST_DATA_INTEGER) \
8889  MEMBER(queue_ent, pos, AST_DATA_INTEGER) \
8890  MEMBER(queue_ent, prio, AST_DATA_INTEGER) \
8891  MEMBER(queue_ent, last_pos_said, AST_DATA_INTEGER) \
8892  MEMBER(queue_ent, last_periodic_announce_time, AST_DATA_INTEGER) \
8893  MEMBER(queue_ent, last_periodic_announce_sound, AST_DATA_INTEGER) \
8894  MEMBER(queue_ent, last_pos, AST_DATA_INTEGER) \
8895  MEMBER(queue_ent, opos, AST_DATA_INTEGER) \
8896  MEMBER(queue_ent, handled, AST_DATA_INTEGER) \
8897  MEMBER(queue_ent, pending, AST_DATA_INTEGER) \
8898  MEMBER(queue_ent, max_penalty, AST_DATA_INTEGER) \
8899  MEMBER(queue_ent, min_penalty, AST_DATA_INTEGER) \
8900  MEMBER(queue_ent, linpos, AST_DATA_INTEGER) \
8901  MEMBER(queue_ent, linwrapped, AST_DATA_INTEGER) \
8902  MEMBER(queue_ent, start, AST_DATA_INTEGER) \
8903  MEMBER(queue_ent, expire, AST_DATA_INTEGER) \
8904  MEMBER(queue_ent, cancel_answered_elsewhere, AST_DATA_INTEGER)
8905 
8907 
8908 /*!
8909  * \internal
8910  * \brief Add a queue to the data_root node.
8911  * \param[in] search The search tree.
8912  * \param[in] data_root The main result node.
8913  * \param[in] queue The queue to add.
8914  */
8915 static void queues_data_provider_get_helper(const struct ast_data_search *search,
8916  struct ast_data *data_root, struct call_queue *queue)
8917 {
8918  struct ao2_iterator im;
8919  struct member *member;
8920  struct queue_ent *qe;
8921  struct ast_data *data_queue, *data_members = NULL, *enum_node;
8922  struct ast_data *data_member, *data_callers = NULL, *data_caller, *data_caller_channel;
8923 
8924  data_queue = ast_data_add_node(data_root, "queue");
8925  if (!data_queue) {
8926  return;
8927  }
8928 
8929  ast_data_add_structure(call_queue, data_queue, queue);
8930 
8931  ast_data_add_str(data_queue, "strategy", int2strat(queue->strategy));
8932  ast_data_add_int(data_queue, "membercount", ao2_container_count(queue->members));
8933 
8934  /* announce position */
8935  enum_node = ast_data_add_node(data_queue, "announceposition");
8936  if (!enum_node) {
8937  return;
8938  }
8939  switch (queue->announceposition) {
8941  ast_data_add_str(enum_node, "text", "limit");
8942  break;
8944  ast_data_add_str(enum_node, "text", "more");
8945  break;
8946  case ANNOUNCEPOSITION_YES:
8947  ast_data_add_str(enum_node, "text", "yes");
8948  break;
8949  case ANNOUNCEPOSITION_NO:
8950  ast_data_add_str(enum_node, "text", "no");
8951  break;
8952  default:
8953  ast_data_add_str(enum_node, "text", "unknown");
8954  break;
8955  }
8956  ast_data_add_int(enum_node, "value", queue->announceposition);
8957 
8958  /* add queue members */
8959  im = ao2_iterator_init(queue->members, 0);
8960  while ((member = ao2_iterator_next(&im))) {
8961  if (!data_members) {
8962  data_members = ast_data_add_node(data_queue, "members");
8963  if (!data_members) {
8964  ao2_ref(member, -1);
8965  continue;
8966  }
8967  }
8968 
8969  data_member = ast_data_add_node(data_members, "member");
8970  if (!data_member) {
8971  ao2_ref(member, -1);
8972  continue;
8973  }
8974 
8975  ast_data_add_structure(member, data_member, member);
8976 
8977  ao2_ref(member, -1);
8978  }
8979  ao2_iterator_destroy(&im);
8980 
8981  /* include the callers inside the result. */
8982  if (queue->head) {
8983  for (qe = queue->head; qe; qe = qe->next) {
8984  if (!data_callers) {
8985  data_callers = ast_data_add_node(data_queue, "callers");
8986  if (!data_callers) {
8987  continue;
8988  }
8989  }
8990 
8991  data_caller = ast_data_add_node(data_callers, "caller");
8992  if (!data_caller) {
8993  continue;
8994  }
8995 
8996  ast_data_add_structure(queue_ent, data_caller, qe);
8997 
8998  /* add the caller channel. */
8999  data_caller_channel = ast_data_add_node(data_caller, "channel");
9000  if (!data_caller_channel) {
9001  continue;
9002  }
9003 
9004  ast_channel_data_add_structure(data_caller_channel, qe->chan, 1);
9005  }
9006  }
9007 
9008  /* if this queue doesn't match remove the added queue. */
9009  if (!ast_data_search_match(search, data_queue)) {
9010  ast_data_remove_node(data_root, data_queue);
9011  }
9012 }
9013 
9014 /*!
9015  * \internal
9016  * \brief Callback used to generate the queues tree.
9017  * \param[in] search The search pattern tree.
9018  * \retval NULL on error.
9019  * \retval non-NULL The generated tree.
9020  */
9021 static int queues_data_provider_get(const struct ast_data_search *search,
9022  struct ast_data *data_root)
9023 {
9024  struct ao2_iterator i;
9025  struct call_queue *queue, *queue_realtime = NULL;
9026  struct ast_config *cfg;
9027  char *queuename;
9028 
9029  /* load realtime queues. */
9030  cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
9031  if (cfg) {
9032  for (queuename = ast_category_browse(cfg, NULL);
9033  !ast_strlen_zero(queuename);
9034  queuename = ast_category_browse(cfg, queuename)) {
9035  if ((queue = load_realtime_queue(queuename))) {
9036  queue_unref(queue);
9037  }
9038  }
9039  ast_config_destroy(cfg);
9040  }
9041 
9042  /* static queues. */
9043  i = ao2_iterator_init(queues, 0);
9044  while ((queue = ao2_iterator_next(&i))) {
9045  ao2_lock(queue);
9046  if (queue->realtime) {
9047  queue_realtime = load_realtime_queue(queue->name);
9048  if (!queue_realtime) {
9049  ao2_unlock(queue);
9050  queue_unref(queue);
9051  continue;
9052  }
9053  queue_unref(queue_realtime);
9054  }
9055 
9056  queues_data_provider_get_helper(search, data_root, queue);
9057  ao2_unlock(queue);
9058  queue_unref(queue);
9059  }
9061 
9062  return 0;
9063 }
9064 
9065 static const struct ast_data_handler queues_data_provider = {
9068 };
9069 
9070 static const struct ast_data_entry queue_data_providers[] = {
9071  AST_DATA_ENTRY("asterisk/application/queue/list", &queues_data_provider),
9072 };
9073 
9074 static int unload_module(void)
9076  int res;
9077  struct ast_context *con;
9078  struct ao2_iterator q_iter;
9079  struct call_queue *q = NULL;
9080 
9082  res = ast_manager_unregister("QueueStatus");
9083  res |= ast_manager_unregister("Queues");
9084  res |= ast_manager_unregister("QueueRule");
9085  res |= ast_manager_unregister("QueueSummary");
9086  res |= ast_manager_unregister("QueueAdd");
9087  res |= ast_manager_unregister("QueueRemove");
9088  res |= ast_manager_unregister("QueuePause");
9089  res |= ast_manager_unregister("QueueLog");
9090  res |= ast_manager_unregister("QueuePenalty");
9091  res |= ast_manager_unregister("QueueReload");
9092  res |= ast_manager_unregister("QueueReset");
9093  res |= ast_unregister_application(app_aqm);
9094  res |= ast_unregister_application(app_rqm);
9095  res |= ast_unregister_application(app_pqm);
9096  res |= ast_unregister_application(app_upqm);
9097  res |= ast_unregister_application(app_ql);
9098  res |= ast_unregister_application(app);
9108 
9109  res |= ast_data_unregister(NULL);
9110 
9111  if (device_state_sub)
9112  ast_event_unsubscribe(device_state_sub);
9113 
9115 
9116  if ((con = ast_context_find("app_queue_gosub_virtual_context"))) {
9117  ast_context_remove_extension2(con, "s", 1, NULL, 0);
9118  ast_context_destroy(con, "app_queue"); /* leave no trace */
9119  }
9120 
9121  q_iter = ao2_iterator_init(queues, 0);
9122  while ((q = ao2_t_iterator_next(&q_iter, "Iterate through queues"))) {
9123  queues_t_unlink(queues, q, "Remove queue from container due to unload");
9124  queue_t_unref(q, "Done with iterator");
9125  }
9126  ao2_iterator_destroy(&q_iter);
9127  devicestate_tps = ast_taskprocessor_unreference(devicestate_tps);
9128  ao2_ref(queues, -1);
9129  ast_unload_realtime("queue_members");
9130  return res;
9131 }
9132 
9133 static int load_module(void)
9135  int res;
9136  struct ast_context *con;
9137  struct ast_flags mask = {AST_FLAGS_ALL, };
9138 
9140 
9141  use_weight = 0;
9142 
9143  if (reload_handler(0, &mask, NULL))
9144  return AST_MODULE_LOAD_DECLINE;
9145 
9146  con = ast_context_find_or_create(NULL, NULL, "app_queue_gosub_virtual_context", "app_queue");
9147  if (!con)
9148  ast_log(LOG_ERROR, "Queue virtual context 'app_queue_gosub_virtual_context' does not exist and unable to create\n");
9149  else
9150  ast_add_extension2(con, 1, "s", 1, NULL, NULL, "NoOp", ast_strdup(""), ast_free_ptr, "app_queue");
9151 
9152  if (queue_persistent_members)
9154 
9156 
9159  res |= ast_register_application_xml(app_aqm, aqm_exec);
9160  res |= ast_register_application_xml(app_rqm, rqm_exec);
9161  res |= ast_register_application_xml(app_pqm, pqm_exec);
9162  res |= ast_register_application_xml(app_upqm, upqm_exec);
9163  res |= ast_register_application_xml(app_ql, ql_exec);
9164  res |= ast_manager_register_xml("Queues", 0, manager_queues_show);
9165  res |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status);
9166  res |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary);
9172  res |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show);
9173  res |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload);
9174  res |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset);
9184 
9185  if (!(devicestate_tps = ast_taskprocessor_get("app_queue", 0))) {
9186  ast_log(LOG_WARNING, "devicestate taskprocessor reference failed - devicestate notifications will not occur\n");
9187  }
9188 
9189  /* in the following subscribe call, do I use DEVICE_STATE, or DEVICE_STATE_CHANGE? */
9190  if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, "AppQueue Device state", NULL, AST_EVENT_IE_END))) {
9191  res = -1;
9192  }
9193 
9194  ast_extension_state_add(NULL, NULL, extension_state_cb, NULL);
9195 
9196  ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, SENTINEL);
9197 
9198  return res ? AST_MODULE_LOAD_DECLINE : 0;
9199 }
9200 
9201 static int reload(void)
9203  struct ast_flags mask = {AST_FLAGS_ALL & ~QUEUE_RESET_STATS,};
9204  ast_unload_realtime("queue_members");
9205  reload_handler(1, &mask, NULL);
9206  return 0;
9207 }
9208 
9210  .load = load_module,
9211  .unload = unload_module,
9212  .reload = reload,
9213  .load_pri = AST_MODPRI_DEVSTATE_CONSUMER,
9214  .nonoptreq = "res_monitor",
9215  );
const char * type
Definition: datastore.h:32
static int get_member_penalty(char *queuename, char *interface)
Definition: app_queue.c:5940
struct ast_str * sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS]
Definition: app_queue.c:1268
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition: pbx.c:4676
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:6781
int ast_safe_sleep(struct ast_channel *chan, int ms)
Wait for a specified amount of time, looking for hangups.
Definition: channel.c:1916
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:3534
union ast_frame_subclass subclass
Definition: frame.h:146
#define ao2_t_find(arg1, arg2, arg3, arg4)
Definition: astobj2.h:963
struct callattempt * q_next
Definition: app_queue.c:1121
int ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2804
int queuepos
Definition: app_queue.c:1186
enum sip_cc_notify_state state
Definition: chan_sip.c:842
Options for ast_pbx_run()
Definition: pbx.h:336
void ast_party_connected_line_init(struct ast_party_connected_line *init)
Initialize the given connected line structure.
Definition: channel.c:2308
static char accountcode[AST_MAX_ACCOUNT_CODE]
Definition: chan_iax2.c:383
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:7589
static int say_position(struct queue_ent *qe, int ringing)
Definition: app_queue.c:2849
const char * ast_devstate2str(enum ast_device_state devstate) attribute_pure
Find devicestate as text message for output.
Definition: devicestate.c:215
int servicelevel
Definition: app_queue.c:1299
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:7051
struct call_queue * parent
Definition: app_queue.c:1144
char moh[80]
Definition: app_queue.c:1145
#define ast_channel_lock(chan)
Definition: channel.h:2466
#define X_REC_IN
Definition: monitor.h:35
int dynamic
Definition: app_queue.c:1182
int ast_cdr_isset_unanswered(void)
Definition: cdr.c:185
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:109
Main Channel structure associated with a channel.
Definition: channel.h:742
char accountcode[AST_MAX_ACCOUNT_CODE]
Definition: cdr.h:114
static struct ast_custom_function queuewaitingcount_function
Definition: app_queue.c:7112
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:2628
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:191
ast_device_state
Device States.
Definition: devicestate.h:51
void ast_cdr_failed(struct ast_cdr *cdr)
Fail a call.
Definition: cdr.c:764
static int member_hash_fn(const void *obj, const int flags)
Definition: app_queue.c:1843
static int remove_members_and_mark_unfound(void *obj, void *arg, int flags)
Definition: app_queue.c:7432
An event.
Definition: event.c:85
char * str
Subscriber phone number (Malloced)
Definition: channel.h:241
struct ast_party_connected_line connected
Channel Connected Line ID information.
Definition: channel.h:811
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:946
#define MAX_PERIODIC_ANNOUNCEMENTS
Definition: app_queue.c:1027
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
static char * app_ql
Definition: app_queue.c:1049
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:3602
const char *const type
Definition: channel.h:508
Asterisk locking-related definitions:
int autopause
Definition: app_queue.c:1013
ast_extension_states
Extension states.
Definition: pbx.h:60
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:2068
static void queue_transfer_destroy(void *data)
Definition: app_queue.c:4680
Asterisk main include file. File version handling, generic pbx functions.
void ast_poll_channel_add(struct ast_channel *chan0, struct ast_channel *chan1)
Definition: channel.c:2665
#define ao2_link(arg1, arg2)
Definition: astobj2.h:785
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:420
int paused
Definition: app_queue.c:1185
#define RES_OKAY
Definition: app_queue.c:1033
static int rqm_exec(struct ast_channel *chan, const char *data)
RemoveQueueMember application.
Definition: app_queue.c:6139
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
Definition: astobj2.c:470
static int queue_function_queuememberpaused(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: app_queue.c:7033
const char * ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
Gets a variable.
Definition: config.c:625
void(* end_bridge_callback_data_fixup)(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
Definition: channel.h:993
time_t lastcall
Definition: app_queue.c:1126
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:172
static struct ast_custom_function queuememberstatus_function
Definition: app_queue.c:7128
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
char digits[AST_MAX_EXTENSION]
Definition: app_queue.c:1148
static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
Definition: app_queue.c:4776
The data tree to be returned by the callbacks and managed by functions local to this file...
Definition: data.c:85
char * str
Subscriber phone number (Malloced)
Definition: channel.h:336
const ast_string_field sound_holdtime
Definition: app_queue.c:1266
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:7091
unsigned int eventwhencalled
Definition: app_queue.c:1270
struct ast_party_caller caller
Channel Caller ID information.
Definition: channel.h:804
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:179
char * strsep(char **str, const char *delims)
struct ast_channel * chan
Definition: app_queue.c:1168
#define DATA_EXPORT_CALL_QUEUE(MEMBER)
Definition: app_queue.c:8805
struct ast_app * pbx_findapp(const char *app)
Look up an application.
Definition: pbx.c:1537
static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, enum empty_conditions conditions, int devstate)
Check if members are available.
Definition: app_queue.c:1545
int min_penalty
Definition: app_queue.c:1162
int priority
Definition: channel.h:841
int wrapuptime
Definition: app_queue.c:1305
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
Definition: pbx.c:1497
static struct ast_datastore_info queue_transfer_info
a datastore used to help correctly log attended transfers of queue callers
Definition: app_queue.c:4688
static int mark_member_dead(void *obj, void *arg, int flags)
Definition: app_queue.c:7301
const ast_string_field membergosub
Definition: app_queue.c:1266
#define queue_t_unref(a, b)
Definition: app_queue.c:1473
const ast_string_field uniqueid
Definition: channel.h:787
struct ast_flags features_callee
Definition: channel.h:976
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:8326
int max_relative
Definition: app_queue.c:1216
static int load_module(void)
Definition: app_queue.c:9134
static struct ast_data_entry queue_data_providers[]
Definition: app_queue.c:9071
static char * handle_queue_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:8720
struct rule_list::@58 rules
#define ast_strdup(a)
Definition: astmm.h:109
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
Definition: ast_expr2.c:325
static char * app_aqm
Definition: app_queue.c:1041
#define ao2_t_alloc(data_size, destructor_fn, debug_msg)
Allocate and initialize an object.
Definition: astobj2.h:429
int max_penalty
Definition: app_queue.c:1161
char dstchannel[AST_MAX_EXTENSION]
Definition: cdr.h:94
void ast_cdr_reset(struct ast_cdr *cdr, struct ast_flags *flags)
Reset the detail record, optionally posting it first.
Definition: cdr.c:1149
struct ast_party_id id
Connected party ID.
Definition: channel.h:403
int last_periodic_announce_sound
Definition: app_queue.c:1155
#define AST_DIGIT_ANY
Definition: file.h:47
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: cli.c:2177
time_t start
Definition: app_queue.c:1165
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:2329
#define ast_test_flag(p, flag)
Definition: utils.h:63
int option_debug
Definition: asterisk.c:182
int penaltymemberslimit
Definition: app_queue.c:1306
Device state management.
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:6103
int ast_unload_realtime(const char *family)
Release any resources cached for a realtime family.
Definition: config.c:2630
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4393
char name[80]
Definition: app_queue.c:1327
Call Event Logging API.
unsigned int setqueuevar
Definition: app_queue.c:1274
struct ast_party_name name
Subscriber name.
Definition: channel.h:290
#define DEFAULT_RETRY
Definition: app_queue.c:1024
#define ANNOUNCEPOSITION_NO
Definition: app_queue.c:1222
struct ast_party_id from
Who is redirecting the call (Sent to the party the call is redirected toward)
Definition: channel.h:449
int ast_extension_state_del(int id, ast_state_cb_type change_cb)
Deletes a registered state change callback by ID.
Definition: pbx.c:5157
void * ptr
Definition: frame.h:160
static char * complete_queue_pause_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:8492
static void update_realtime_members(struct call_queue *q)
Definition: app_queue.c:2642
static char * handle_queue_remove_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:8446
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:9592
static int reload(void)
Definition: app_queue.c:9202
#define DEFAULT_MIN_ANNOUNCE_FREQUENCY
Definition: app_queue.c:1028
struct call_queue::@57 rules
unsigned int maskmemberstatus
Definition: app_queue.c:1282
int ast_taskprocessor_push(struct ast_taskprocessor *tps, int(*task_exe)(void *datap), void *datap)
Push a task into the specified taskprocessor queue and signal the taskprocessor thread.
char context[AST_MAX_CONTEXT]
Definition: channel.h:868
static int manager_queue_reset(struct mansession *s, const struct message *m)
Definition: app_queue.c:8255
int ast_channel_supports_html(struct ast_channel *channel)
Checks for HTML support on a channel.
Definition: channel.c:5902
static int mark_dead_and_unfound(void *obj, void *arg, int flags)
Definition: app_queue.c:7443
#define ao2_iterator_next(arg1)
Definition: astobj2.h:1126
int min_relative
Definition: app_queue.c:1217
#define ast_set_flag(p, flag)
Definition: utils.h:70
int minannouncefrequency
Definition: app_queue.c:1290
int last_pos_said
Definition: app_queue.c:1152
descriptor for a cli entry.
Definition: cli.h:165
const int argc
Definition: cli.h:154
#define LOG_WARNING
Definition: logger.h:144
int ast_cel_report_event(struct ast_channel *chan, enum ast_cel_event_type event_type, const char *userdefevname, const char *extra, struct ast_channel *peer2)
Report a channel event.
Definition: cel.c:645
struct ast_cdr * next
Definition: cdr.h:132
static int manager_queue_member_penalty(struct mansession *s, const struct message *m)
Definition: app_queue.c:8301
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category)
Goes through variables.
Definition: config.c:597
#define AST_MAX_WATCHERS
Definition: app_queue.c:3775
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
static void member_remove_from_queue(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:2314
int linwrapped
Definition: app_queue.c:1164
struct call_queue * lastqueue
Definition: app_queue.c:1127
void ast_db_freetree(struct ast_db_entry *entry)
Free structure created by ast_db_gettree()
Definition: db.c:656
int ast_add_extension2(struct ast_context *con, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar)
Add an extension to an extension context, this time with an ast_context *.
Definition: pbx.c:9052
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:910
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:9085
struct ast_taskprocessor * ast_taskprocessor_get(const char *name, enum ast_tps_options create)
Get a reference to a taskprocessor with the specified name and create the taskprocessor if necessary...
struct queue_ent * qe
Definition: app_queue.c:4674
int lineno
Definition: config.h:87
int autopause
Definition: app_queue.c:1312
unsigned int ringinuse
Definition: app_queue.c:1271
static int kill_dead_members(void *obj, void *arg, int flags)
Definition: app_queue.c:7310
char dcontext[AST_MAX_EXTENSION]
Definition: cdr.h:90
#define AST_FRAME_DTMF
Definition: frame.h:128
empty_conditions
Definition: app_queue.c:1196
#define RES_NOT_DYNAMIC
Definition: app_queue.c:1037
time_t expire
Definition: app_queue.c:1166
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
#define MAX_QUEUE_BUCKETS
Definition: app_queue.c:1031
This entries are for multiple registers.
Definition: data.h:253
static void member_call_pending_clear(struct member *mem)
Definition: app_queue.c:3264
unsigned int timeoutrestart
Definition: app_queue.c:1278
static int wrapuptime
Definition: chan_agent.c:223
Data retrieval API.
Structure for variables, used for configurations and for channel variables.
Definition: config.h:75
#define var
Definition: ast_expr2f.c:606
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:479
static struct ast_custom_function queuemembercount_dep
Definition: app_queue.c:7107
#define ao2_t_iterator_next(arg1, arg2)
Definition: astobj2.h:1125
globally accessible channel datastores
struct ast_cdr * ast_cdr_dup(struct ast_cdr *cdr)
Duplicate a record.
Definition: cdr.c:213
char uniqueid[150]
Definition: cdr.h:121
static struct callattempt * wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed, int ringing)
Wait for a member to answer the call.
Definition: app_queue.c:3789
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:438
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4383
#define DATA_EXPORT_MEMBER(MEMBER)
Definition: app_queue.c:8870
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:6678
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:4554
struct ast_party_redirecting redirecting
Redirecting/Diversion information.
Definition: channel.h:814
#define EVENT_FLAG_CALL
Definition: manager.h:72
Definition: cli.h:146
void * ast_aoc_destroy_decoded(struct ast_aoc_decoded *decoded)
free an ast_aoc_decoded object
Definition: aoc.c:176
unsigned int announceholdtime
Definition: app_queue.c:1279
Structure for a data store type.
Definition: datastore.h:31
Configuration File Parser.
static int reload_queue_rules(int reload)
Reload the rules defined in queuerules.conf.
Definition: app_queue.c:7144
char * str
Subscriber name (Malloced)
Definition: channel.h:214
unsigned int stop
Definition: app_meetme.c:969
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:4447
struct ast_variable * ast_load_realtime(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: config.c:2548
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: db.c:358
char interface[256]
Definition: app_queue.c:1124
int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
Bridge a call, optionally allowing redirection.
Definition: features.c:3960
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:900
static int attended_transfer_occurred(struct ast_channel *chan)
mechanism to tell if a queue caller was atxferred by a queue member.
Definition: app_queue.c:4735
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:7603
static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, int newtalktime)
update the queue status
Definition: app_queue.c:4506
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:142
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:235
struct ast_str * ast_str_create(size_t init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:420
#define AST_OPTION_TONE_VERIFY
Definition: frame.h:441
static void reload_single_member(const char *memberdata, struct call_queue *q)
reload information pertaining to a single member
Definition: app_queue.c:7226
queue_result
Definition: app_queue.c:1078
int realtime
Definition: app_queue.c:1183
char interface[80]
Definition: app_queue.c:1175
#define ast_assert(a)
Definition: utils.h:738
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:2135
struct ast_cdr * cdr
Definition: channel.h:766
char state_interface[80]
Definition: app_queue.c:1178
#define ao2_unlock(a)
Definition: astobj2.h:497
unsigned int setinterfacevar
Definition: app_queue.c:1273
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags)
Create an iterator for a container.
Definition: astobj2.c:818
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:374
static int set_member_penalty(const char *queuename, const char *interface, int penalty)
Definition: app_queue.c:5891
char * text
Definition: app_queue.c:1091
format_t nativeformats
Definition: channel.h:852
#define ast_str_alloca(init_len)
Definition: strings.h:608
Structure for a data store object.
Definition: datastore.h:54
void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
Destroy the connected line information contents.
Definition: channel.c:2353
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2604
static void set_queue_result(struct ast_channel *chan, enum queue_result res)
sets the QUEUESTATUS channel variable
Definition: app_queue.c:1341
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: config.c:586
const char * str
Definition: app_jack.c:144
int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *connected_info, int caller, int frame)
Run a connected line interception macro and update a channel&#39;s connected line information.
Definition: channel.c:9618
static struct strategy strategies[]
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:6907
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:1433
unsigned int dead
Definition: app_queue.c:1189
struct ast_aoc_decoded * aoc_s_rate_list
Definition: app_queue.c:1139
static int say_periodic_announcement(struct queue_ent *qe, int ringing)
Playback announcement to queued members if period has elapsed.
Definition: app_queue.c:3650
const char * data
Definition: channel.h:755
const ast_string_field sound_thanks
Definition: app_queue.c:1266
static void clear_queue(struct call_queue *q)
Definition: app_queue.c:1943
int ringlimit
Definition: app_queue.c:1307
int value
Definition: syslog.c:39
void ast_cli(int fd, const char *fmt,...)
Definition: cli.c:105
static int can_ring_entry(struct queue_ent *qe, struct callattempt *call)
Definition: app_queue.c:3300
void ast_monitor_setjoinfiles(struct ast_channel *chan, int turnon)
Definition: res_monitor.c:867
#define LOG_DEBUG
Definition: logger.h:122
static char * app_rqm
Definition: app_queue.c:1043
#define AST_DATA_ENTRY(__path, __handler)
Definition: data.h:260
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:7795
static char * queue_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:7852
unsigned int delme
Definition: app_queue.c:1191
#define ast_module_user_remove(user)
Definition: module.h:269
enum ast_channel_adsicpe adsicpe
Definition: channel.h:844
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx.c:7705
unsigned int announce_to_first_user
Definition: app_queue.c:1272
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:8051
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:600
struct ao2_container * members
Definition: app_queue.c:1320
void ast_free_ptr(void *ptr)
struct queue_ent * head
Definition: app_queue.c:1321
char monfmt[8]
Definition: app_queue.c:1301
#define ast_verb(level,...)
Definition: logger.h:243
static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
Definition: app_queue.c:2993
int callscompletedinsl
Definition: app_queue.c:1300
Definition: ael.tab.c:203
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: config.c:1037
const ast_string_field membermacro
Definition: app_queue.c:1266
const char * appl
Definition: channel.h:754
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return * the previous value of *p. This can be used to handle reference co...
Definition: lock.h:603
int announcepositionlimit
Definition: app_queue.c:1288
static int insert_penaltychange(const char *list_name, const char *content, const int linenum)
Change queue penalty by adding rule.
Definition: app_queue.c:1972
const char * line
Definition: cli.h:156
static struct ast_custom_function queueexists_function
Definition: app_queue.c:7092
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
Definition: pbx.c:3814
char membername[80]
Definition: app_queue.c:1179
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:65
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:5415
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
Definition: pbx.c:10475
#define X_REC_OUT
Definition: monitor.h:36
static int strat2int(const char *strategy)
Definition: app_queue.c:1365
static int queue_function_queuememberstatus(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: app_queue.c:6974
#define RES_OUTOFMEMORY
Definition: app_queue.c:1035
String fields in structures.
Utility functions.
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:1860
static int member_status_available(int status)
Definition: app_queue.c:3251
#define ast_manager_event(chan, category, event, contents,...)
Definition: manager.h:221
static char * app
Definition: app_queue.c:1039
unsigned int wrapped
Definition: app_queue.c:1277
static int manager_queue_rule_show(struct mansession *s, const struct message *m)
Definition: app_queue.c:7881
static struct member * interface_exists(struct call_queue *q, const char *interface)
Definition: app_queue.c:5637
static int wait_a_bit(struct queue_ent *qe)
Definition: app_queue.c:5625
static int compare_weight(struct call_queue *rq, struct member *member)
Definition: app_queue.c:3163
static const char qum_cmd_usage[]
Definition: app_queue.c:8787
int holdtime
Definition: app_queue.c:1295
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:874
struct ast_party_id id
Caller party ID.
Definition: channel.h:370
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:6631
static void device_state_cb(const struct ast_event *event, void *unused)
Definition: app_queue.c:1699
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:6938
char lastdata[AST_MAX_EXTENSION]
Definition: cdr.h:98
int ast_update_realtime(const char *family, const char *keyfield, const char *lookup,...) attribute_sentinel
Update realtime configuration.
Definition: config.c:2679
struct ast_cdr * ast_cdr_append(struct ast_cdr *cdr, struct ast_cdr *newcdr)
Definition: cdr.c:1216
long int amaflags
Definition: cdr.h:112
int ast_channel_datastore_inherit(struct ast_channel *from, struct ast_channel *to)
Inherit datastores from a parent to a child.
Definition: channel.c:2573
static struct ast_taskprocessor * devicestate_tps
Definition: app_queue.c:1022
#define ast_asprintf(a, b, c...)
Definition: astmm.h:121
static int queue_function_qac(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:6702
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
int ast_channel_data_add_structure(struct ast_data *tree, struct ast_channel *chan, int add_bridged)
Insert into an astdata tree, the channel structure.
Definition: channel.c:357
static void member_add_to_queue(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:2300
static char * complete_queue_set_member_penalty(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:8562
#define SENTINEL
Definition: compiler.h:75
struct ast_db_entry * next
Definition: astdb.h:31
#define AST_DATA_HANDLER_VERSION
The Data API structures version.
Definition: data.h:204
Generic Advice of Charge encode and decode routines.
const ast_string_field sound_minute
Definition: app_queue.c:1266
const char * value
Definition: config.h:79
struct ast_party_connected_line connected
Definition: app_queue.c:1130
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:318
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:2093
static struct ast_custom_function queuemembercount_function
Definition: app_queue.c:7102
struct ast_party_id ani
Automatic Number Identification (ANI)
Definition: channel.h:377
agent_complete_reason
Definition: app_queue.c:4630
int periodicannouncefrequency
Definition: app_queue.c:1291
static struct ao2_container * queues
Definition: app_queue.c:1334
static void end_bridge_callback(void *data)
Definition: app_queue.c:4783
static char * vars2manager(struct ast_channel *chan, char *vars, size_t len)
convert &quot;\n&quot; to &quot;\nVariable: &quot; ready for manager to use
Definition: app_queue.c:3206
General Asterisk PBX channel definitions.
static char dialcontext[AST_MAX_CONTEXT]
struct ast_party_dialed::@155 number
Dialed/Called number.
int penalty
Definition: app_queue.c:1180
static struct ast_custom_function queuememberpenalty_function
Definition: app_queue.c:7122
static int pqm_exec(struct ast_channel *chan, const char *data)
PauseQueueMember application.
Definition: app_queue.c:6067
int memberdelay
Definition: app_queue.c:1317
const int fd
Definition: cli.h:153
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:249
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:7807
#define ast_config_load(filename, flags)
Load a config file.
Definition: config.h:170
struct call_queue * q
Definition: app_queue.c:4772
#define ast_manager_register_xml(a, b, c)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:172
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
const int n
Definition: cli.h:159
struct ast_datastore_info dialed_interface_info
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:519
unsigned int block_connected_update
Definition: app_queue.c:1134
static void parse_empty_options(const char *value, enum empty_conditions *empty, int joinempty)
Definition: app_queue.c:2050
const ast_string_field sound_thereare
Definition: app_queue.c:1266
Data structure associated with a custom dialplan function.
Definition: pbx.h:95
int ring_when_ringing
Definition: app_queue.c:1153
static void free_members(struct call_queue *q, int all)
Iterate through queue&#39;s member list and delete them.
Definition: app_queue.c:2388
enum ast_pbx_result ast_pbx_run_args(struct ast_channel *c, struct ast_pbx_args *args)
Execute the PBX in the current thread.
Definition: pbx.c:5906
struct ast_data * ast_data_add_node(struct ast_data *root, const char *childname)
Add a container child.
Definition: data.c:2317
char linkedid[32]
Definition: cdr.h:123
#define AST_MAX_EXTENSION
Definition: channel.h:135
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:155
int datalen
Definition: frame.h:148
const ast_string_field context
Definition: app_queue.c:1266
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:220
#define ast_data_unregister(path)
Definition: data.h:394
void ast_party_number_init(struct ast_party_number *init)
Initialize the given number structure.
Definition: channel.c:1981
bridge configuration
Definition: channel.h:974
void * end_bridge_callback_data
Definition: channel.h:989
Caller Party information.
Definition: channel.h:368
char * ast_category_browse(struct ast_config *config, const char *prev)
Goes through categories.
Definition: config.c:810
#define ao2_ref(o, delta)
Definition: astobj2.h:472
#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:83
static int reload_handler(int reload, struct ast_flags *mask, const char *queuename)
The command center for all reload operations.
Definition: app_queue.c:7572
long int ast_random(void)
Definition: utils.c:1640
static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere)
Hang up a list of outgoing calls.
Definition: app_queue.c:3090
#define ao2_lock(a)
Definition: astobj2.h:488
const ast_string_field sound_next
Definition: app_queue.c:1266
int valid_digits
Definition: app_queue.c:1149
struct member * member
Definition: app_queue.c:1128
static struct callattempt * find_best(struct callattempt *outgoing)
find the entry with the best metric, or NULL
Definition: app_queue.c:3540
char dst[AST_MAX_EXTENSION]
Definition: cdr.h:88
A set of macros to manage forward-linked lists.
const char * name
Definition: config.h:77
int ast_monitor_start(struct ast_channel *chan, const char *format_spec, const char *fname_base, int need_lock, int stream_action)
Start monitoring a channel.
Definition: res_monitor.c:290
int strategy
Definition: app_queue.c:1281
static void queue_set_global_params(struct ast_config *cfg)
Definition: app_queue.c:7193
char channel[AST_MAX_EXTENSION]
Definition: cdr.h:92
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
struct call_queue * lastqueue
Definition: app_queue.c:1188
static int unload_module(void)
Definition: app_queue.c:9075
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:5400
struct ast_party_id ani
Automatic Number Identification (ANI)
Definition: channel.h:410
#define ast_data_register_multiple(data_entries, entries)
Definition: data.h:377
#define ANNOUNCEPOSITION_MORE_THAN
Definition: app_queue.c:1223
int linpos
Definition: app_queue.c:1163
static int handle_statechange(void *datap)
set a member&#39;s status based on device state of that member&#39;s interface
Definition: app_queue.c:1655
#define ast_module_user_add(chan)
Definition: module.h:268
char dev[0]
Definition: app_queue.c:1622
Core PBX routines and definitions.
static struct autopause autopausesmodes[]
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:238
void ast_party_number_free(struct ast_party_number *doomed)
Destroy the party number contents.
Definition: channel.c:2028
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:806
static int queue_member_decrement_followers(void *obj, void *arg, int flag)
Definition: app_queue.c:1415
struct ast_flags features_caller
Definition: channel.h:975
#define ast_data_add_structure(structure_name, root, structure)
Definition: data.h:620
The list of nodes with their search requirement.
Definition: data.c:122
#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
const char *const * argv
Definition: cli.h:155
static int num_available_members(struct call_queue *q)
Get the number of members available to accept a call.
Definition: app_queue.c:3117
static char * handle_queue_rule_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:8647
struct ast_party_dialed dialed
Dialed/Called information.
Definition: channel.h:797
static int montype_default
queues.conf [general] option
Definition: app_queue.c:1067
static void leave_queue(struct queue_ent *qe)
Caller leaving queue.
Definition: app_queue.c:3012
static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
Part 2 of ring_one.
Definition: app_queue.c:3368
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:224
We define a custom &quot;local user&quot; structure because we use it not only for keeping track of what is i...
Definition: app_queue.c:1120
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
void * obj
Definition: astobj2.h:1063
static int member_cmp_fn(void *obj1, void *obj2, int flags)
Definition: app_queue.c:1855
static char * complete_queue_rule_show(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:8625
static void destroy_queue(void *obj)
Free queue&#39;s member list then its string fields.
Definition: app_queue.c:2404
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:8886
Responsible for call detail data.
Definition: cdr.h:82
static int queue_cmp_cb(void *obj, void *arg, int flags)
Definition: app_queue.c:1404
char lastapp[AST_MAX_EXTENSION]
Definition: cdr.h:96
static int autofill_default
queues.conf [general] option
Definition: app_queue.c:1064
#define LOG_ERROR
Definition: logger.h:155
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
static int manager_queue_log_custom(struct mansession *s, const struct message *m)
Definition: app_queue.c:8202
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is &quot;true&quot;. This function checks to see whether a string passed to it is an indication of an &quot;true&quot; value. It checks to see if the string is &quot;yes&quot;, &quot;true&quot;, &quot;y&quot;, &quot;t&quot;, &quot;on&quot; or &quot;1&quot;.
Definition: utils.c:1533
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:2288
static int manager_queue_reload(struct mansession *s, const struct message *m)
Definition: app_queue.c:8223
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
Definition: app_queue.c:2700
#define free(a)
Definition: astmm.h:94
#define ANNOUNCEPOSITION_YES
Definition: app_queue.c:1221
unsigned int dead
Definition: app_queue.c:1269
static struct @350 args
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:7748
struct ast_db_entry * ast_db_gettree(const char *family, const char *keytree)
Get a list of values within the astdb tree If family is specified, only those keys will be returned...
Definition: db.c:631
#define CLI_SHOWUSAGE
Definition: cli.h:44
void ast_data_remove_node(struct ast_data *root, struct ast_data *child)
Remove a node that was added using ast_data_add_.
Definition: data.c:2486
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition: utils.c:1615
static struct ast_custom_function queuememberlist_function
Definition: app_queue.c:7117
static struct call_queue * load_realtime_queue(const char *queuename)
Definition: app_queue.c:2573
const ast_string_field name
Definition: app_queue.c:1266
static struct ast_datastore * setup_transfer_datastore(struct queue_ent *qe, struct member *member, time_t starttime, int callcompletedinsl)
create a datastore for storing relevant info to log attended transfers in the queue_log ...
Definition: app_queue.c:4742
const ast_string_field call_forward
Definition: channel.h:787
Event subscription.
Definition: event.c:124
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:2337
unsigned int reportholdtime
Definition: app_queue.c:1276
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:4773
enum ast_channel_state _state
Definition: channel.h:839
static void rt_handle_member_record(struct call_queue *q, char *interface, const char *rt_uniqueid, const char *membername, const char *penalty_str, const char *paused_str, const char *state_interface)
Find rt member record to update otherwise create one.
Definition: app_queue.c:2328
int autofill
Definition: app_queue.c:1318
queue_reload_mask
Definition: app_queue.c:990
static int extensionstate2devicestate(int state)
Helper function which converts from extension state to device state values.
Definition: app_queue.c:1726
Connected Line/Party information.
Definition: channel.h:401
const ast_string_field name
Definition: channel.h:787
unsigned int pending_connected_update
Definition: app_queue.c:1132
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...
Definition: pbx.c:10633
static int try_calling(struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *tries, int *noption, const char *agi, const char *macro, const char *gosub, int ringing)
A large function which calls members, updates statistics, and bridges the caller and a member...
Definition: app_queue.c:4823
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:8040
int talktime
Definition: app_queue.c:1296
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static float di[4]
Definition: tdd.c:59
int _softhangup
Definition: channel.h:832
#define EVENT_FLAG_AGENT
Definition: manager.h:76
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:430
static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
Definition: app_queue.c:5814
struct ast_datastore * ast_datastore_alloc(const struct ast_datastore_info *info, const char *uid)
Definition: datastore.c:98
time_t last_pos
Definition: app_queue.c:1156
static int ql_exec(struct ast_channel *chan, const char *data)
QueueLog application.
Definition: app_queue.c:6258
Redirecting Line information. RDNIS (Redirecting Directory Number Information Service) Where a call d...
Definition: channel.h:447
#define LOG_NOTICE
Definition: logger.h:133
#define DATA_EXPORT_QUEUE_ENT(MEMBER)
Definition: app_queue.c:8884
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:11261
int roundingseconds
Definition: app_queue.c:1294
static void dump_queue_members(struct call_queue *pm_queue)
Dump all members in a specific queue to the database.
Definition: app_queue.c:5663
static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
Log an attended transfer when a queue caller channel is masqueraded.
Definition: app_queue.c:4703
Definition: astdb.h:30
#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 char * app_pqm
Definition: app_queue.c:1045
static struct call_queue * queue_unref(struct call_queue *q)
Definition: app_queue.c:1482
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:5914
static struct call_queue * alloc_queue(const char *queuename)
Definition: app_queue.c:2418
#define ao2_find(arg1, arg2, arg3)
Definition: astobj2.h:964
#define ast_channel_unlock(chan)
Definition: channel.h:2467
#define CLI_FAILURE
Definition: cli.h:45
int errno
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1858
static const char name[]
#define AST_MAX_CONTEXT
Definition: channel.h:136
static int member_call_pending_set(struct member *mem)
Definition: app_queue.c:3279
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
Definition: linkedlists.h:611
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:6241
int source
Information about the source of an update.
Definition: channel.h:424
#define ast_free(a)
Definition: astmm.h:97
char * command
Definition: cli.h:180
static char * complete_queue_remove_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:8400
#define AST_CHANNEL_NAME
Definition: channel.h:137
struct ast_config * ast_config_new(void)
Create a new base configuration structure.
Definition: config.c:888
static int play_file(struct ast_channel *chan, const char *filename)
Definition: app_queue.c:2787
#define AST_FLAGS_ALL
Definition: utils.h:196
#define queues_t_link(c, q, tag)
Definition: app_queue.c:1474
#define queue_t_ref(a, b)
Definition: app_queue.c:1472
unsigned int call_pending
Definition: app_queue.c:1192
static struct ast_format f[]
Definition: format_g726.c:181
const ast_string_field moh
Definition: app_queue.c:1266
const char * word
Definition: cli.h:157
void * ast_aoc_destroy_encoded(struct ast_aoc_encoded *encoded)
free an ast_aoc_encoded object
Definition: aoc.c:182
const char * name
Definition: app_queue.c:1014
static char * complete_queue_add_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:8270
#define DEFAULT_TIMEOUT
Definition: app_queue.c:1025
int ast_call(struct ast_channel *chan, char *addr, int timeout)
Make a call.
Definition: channel.c:5761
static int manager_queues_status(struct mansession *s, const struct message *m)
Queue status info via AMI.
Definition: app_queue.c:7991
#define DATASTORE_INHERIT_FOREVER
Definition: channel.h:156
int timeoutpriority
Definition: app_queue.c:1313
const ast_string_field defaultrule
Definition: app_queue.c:1266
An API for managing task processing threads that can be shared across modules.
unsigned int inheritance
Definition: datastore.h:58
const ast_string_field sound_seconds
Definition: app_queue.c:1266
static const char qpm_cmd_usage[]
Definition: app_queue.c:8784
struct penalty_rule * pr
Definition: app_queue.c:1170
void ao2_iterator_destroy(struct ao2_iterator *i)
Destroy a container iterator.
Definition: astobj2.c:833
Structure used to handle boolean flags.
Definition: utils.h:200
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:4430
static struct call_queue * queue_ref(struct call_queue *q)
Definition: app_queue.c:1476
int ast_realtime_require_field(const char *family,...) attribute_sentinel
Inform realtime what fields that may be stored.
Definition: config.c:2606
unsigned int announceposition
Definition: app_queue.c:1280
#define ast_clear_flag(p, flag)
Definition: utils.h:77
static int manager_queues_show(struct mansession *s, const struct message *m)
Definition: app_queue.c:7871
int pending
Definition: app_queue.c:1160
unsigned int found
Definition: app_queue.c:1284
static int manager_queues_summary(struct mansession *s, const struct message *m)
Summary of queue info via the AMI.
Definition: app_queue.c:7916
const char * usage
Definition: cli.h:171
char src[AST_MAX_EXTENSION]
Definition: cdr.h:86
int randomperiodicannounce
Definition: app_queue.c:1293
int calls
Definition: app_queue.c:1181
static struct ast_custom_function queuememberpaused_function
Definition: app_queue.c:7133
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...
Definition: pbx.c:10546
uint32_t ast_event_get_ie_uint(const struct ast_event *event, enum ast_event_ie_type ie_type)
Get the value of an information element that has an integer payload.
Definition: event.c:1075
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:6857
char macroexten[AST_MAX_EXTENSION]
Definition: channel.h:871
#define RES_NOSUCHQUEUE
Definition: app_queue.c:1036
#define ANNOUNCEHOLDTIME_ALWAYS
Definition: app_queue.c:1208
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3552
int status
Definition: app_queue.c:1184
unsigned int setqueueentryvar
Definition: app_queue.c:1275
static const char qsmp_cmd_usage[]
Definition: app_queue.c:8790
#define ast_channel_lock_both(chan1, chan2)
Lock two channels.
Definition: channel.h:2473
static struct ast_cli_entry cli_queue[]
Definition: app_queue.c:8793
#define CLI_SUCCESS
Definition: cli.h:43
const ast_string_field announce
Definition: app_queue.c:1266
const ast_string_field sound_reporthold
Definition: app_queue.c:1266
static void callattempt_free(struct callattempt *doomed)
Definition: app_queue.c:3080
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:471
struct member * member
Definition: app_queue.c:4675
void * data
Definition: datastore.h:56
int callsabandoned
Definition: app_queue.c:1298
void ast_poll_channel_del(struct ast_channel *chan0, struct ast_channel *chan1)
Definition: channel.c:2688
int transit_network_select
Transit Network Select.
Definition: channel.h:347
#define ANNOUNCEPOSITION_LIMIT
Definition: app_queue.c:1224
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:3626
void ast_party_redirecting_free(struct ast_party_redirecting *doomed)
Destroy the redirecting information contents.
Definition: channel.c:2396
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:2316
A ast_taskprocessor structure is a singleton by name.
Definition: taskprocessor.c:67
static void record_abandoned(struct queue_ent *qe)
Record that a caller gave up on waiting in queue.
Definition: app_queue.c:3706
static void send_agent_complete(const struct queue_ent *qe, const char *queuename, const struct ast_channel *peer, const struct member *member, time_t callstart, char *vars, size_t vars_len, enum agent_complete_reason rsn)
Send out AMI message with member call completion status information.
Definition: app_queue.c:4637
const ast_string_field sound_calls
Definition: app_queue.c:1266
int numperiodicannounce
Definition: app_queue.c:1292
int ast_channel_make_compatible(struct ast_channel *c0, struct ast_channel *c1)
Makes two channel formats compatible.
Definition: channel.c:5970
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1053
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:8397
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:2442
time_t last_periodic_announce_time
Definition: app_queue.c:1154
static int queue_debug
queues.conf [general] extra debug option
Definition: app_queue.c:1055
static struct ast_custom_function queuevar_function
Definition: app_queue.c:7097
int ast_db_del(const char *family, const char *key)
Delete entry in astdb.
Definition: db.c:365
#define ast_calloc(a, b)
Definition: astmm.h:82
struct ast_event_sub * ast_event_subscribe(enum ast_event_type event_type, ast_event_cb_t cb, const char *description, void *userdata,...)
Subscribe to events.
Definition: event.c:909
static struct member * create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface)
allocate space for new queue member and set fields based on parameters passed
Definition: app_queue.c:1801
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
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:8443
char rt_uniqueid[80]
Definition: app_queue.c:1193
#define ao2_container_alloc(arg1, arg2, arg3)
Definition: astobj2.h:734
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:4914
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:1515
static int autopause2int(const char *autopause)
Definition: app_queue.c:1377
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:77
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
ast_app: A registered application
Definition: pbx.c:971
void ast_cdr_noanswer(struct ast_cdr *cdr)
A call wasn&#39;t answered.
Definition: cdr.c:776
unsigned int realtime
Definition: app_queue.c:1283
void ast_party_redirecting_init(struct ast_party_redirecting *init)
Initialize the given redirecting structure.
Definition: channel.c:2359
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is &quot;false&quot;...
Definition: utils.c:1550
static int compress_char(const char c)
Definition: app_queue.c:1833
int ast_cli_register_multiple(struct ast_cli_entry *e, int len)
Register multiple commands.
Definition: cli.c:2167
const int pos
Definition: cli.h:158
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1343
static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
Set variables of queue.
Definition: app_queue.c:1490
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:919
queue_timeout_priority
Definition: app_queue.c:1103
Channel monitoring.
static int aqm_exec(struct ast_channel *chan, const char *data)
AddQueueMember application.
Definition: app_queue.c:6195
static struct ast_event_sub * device_state_sub
Subscription to device state change events.
Definition: app_queue.c:1073
char state_context[AST_MAX_CONTEXT]
Definition: app_queue.c:1177
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
static struct ast_data_handler queues_data_provider
Definition: app_queue.c:9066
const ast_string_field accountcode
Definition: channel.h:787
int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar, int already_locked)
This functionc locks given context, search for the right extension and fires out all peer in this ext...
Definition: pbx.c:6144
Data structure associated with a single frame of data.
Definition: frame.h:142
#define AST_DATA_STRUCTURE(__struct, __name)
Definition: data.h:300
int hangupcause
Definition: channel.h:849
Internal Asterisk hangup causes.
void ast_context_destroy(struct ast_context *con, const char *registrar)
Destroy a context (matches the specified context (or ANY context if NULL)
Definition: pbx.c:9875
enum empty_conditions leavewhenempty
Definition: app_queue.c:1287
static int use_weight
queues.conf per-queue weight option
Definition: app_queue.c:1061
Definition: aoc.h:64
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:7333
#define RES_EXISTS
Definition: app_queue.c:1034
const char * name
Definition: pbx.h:96
int ast_db_put(const char *family, const char *key, const char *value)
Store value addressed by family/key.
Definition: db.c:260
struct queue_ent::@54 qe_rules
struct queue_ent * next
Definition: app_queue.c:1171
struct timeval whentohangup
Definition: channel.h:789
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:761
unsigned int relativeperiodicannounce
Definition: app_queue.c:1285
static int get_queue_member_status(struct member *cur)
Return the current state of a member.
Definition: app_queue.c:1795
enum queue_result id
Definition: app_queue.c:1090
uint32_t uint32
Definition: frame.h:160
static int kill_dead_queues(void *obj, void *arg, int flags)
Definition: app_queue.c:7454
#define AST_APP_ARG(name)
Define an application argument.
Definition: app.h:555
#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
Definition: frame.h:144
struct ast_variable * next
Definition: config.h:82
static const char *const pm_family
Persistent Members astdb family.
Definition: app_queue.c:1052
static int queue_exec(struct ast_channel *chan, const char *data)
The starting point for all queue calls.
Definition: app_queue.c:6332
#define RECHECK
Definition: app_queue.c:1026
static void reload_queue_members(void)
Reload dynamic queue members persisted into the astdb.
Definition: app_queue.c:5972
const ast_string_field sound_minutes
Definition: app_queue.c:1266
static int queue_hash_cb(const void *obj, const int flags)
Definition: app_queue.c:1397
static void rna(int rnatime, struct queue_ent *qe, char *interface, char *membername, int pause)
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:3723
char context[AST_MAX_CONTEXT]
Definition: app_queue.c:1147
#define ast_frfree(fr)
Definition: frame.h:583
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:669
static void do_hang(struct callattempt *o)
common hangup actions
Definition: app_queue.c:3198
struct callattempt * call_next
Definition: app_queue.c:1122
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:229
static int manager_add_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:8093
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
Definition: app.h:604
char clid[AST_MAX_EXTENSION]
Definition: cdr.h:84
const ast_string_field queue_quantity2
Definition: app_queue.c:1266
#define CONFIG_STATUS_FILEINVALID
Definition: config.h:52
static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface)
Add member to queue.
Definition: app_queue.c:5763
static void init_queue(struct call_queue *q)
Initialize Queue default values.
Definition: app_queue.c:1865
Call Parking and Pickup API Includes code and algorithms from the Zapata library. ...
int handled
Definition: app_queue.c:1158
int cancel_answered_elsewhere
Definition: app_queue.c:1167
static int extension_state_cb(char *context, char *exten, enum ast_extension_states state, void *data)
Definition: app_queue.c:1757
#define ANNOUNCEHOLDTIME_ONCE
Definition: app_queue.c:1209
struct ast_context * ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
Register a new context or find an existing one.
Definition: pbx.c:7726
#define AST_LIST_INSERT_BEFORE_CURRENT(elm, field)
Inserts a list entry before the current entry during a traversal.
Definition: linkedlists.h:584
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:6821
int ast_extension_state_add(const char *context, const char *exten, ast_state_cb_type change_cb, void *data)
Registers a state change callback.
Definition: pbx.c:5135
void(* end_bridge_callback)(void *)
Definition: channel.h:988
static int remove_from_queue(const char *queuename, const char *interface)
Remove member from queue.
Definition: app_queue.c:5715
static int 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:1630
static char * handle_queue_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:8681
Generic State IE Used by AST_EVENT_DEVICE_STATE_CHANGE Payload type: UINT The actual state values dep...
Definition: event_defs.h:115
const char * ast_event_get_ie_str(const struct ast_event *event, enum ast_event_ie_type ie_type)
Get the value of an information element that has a string payload.
Definition: event.c:1102
static void copy_rules(struct queue_ent *qe, const char *rulename)
Copy rule from global list into specified queue.
Definition: app_queue.c:6292
static char url[512]
static void queue_member_follower_removal(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:1451
static void update_qe_rule(struct queue_ent *qe)
update rules for queues
Definition: app_queue.c:4367
Say numbers and dates (maybe words one day too)
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:38
unsigned int dial_callerid_absent
Definition: app_queue.c:1136
enum empty_conditions joinempty
Definition: app_queue.c:1286
#define manager_event(category, event, contents,...)
External routines may send asterisk manager events this way.
Definition: manager.h:219
static char * handle_queue_set_member_penalty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:8585
#define RESULT_SUCCESS
Definition: cli.h:39
struct ast_channel * chan
Definition: app_queue.c:1123
#define ast_malloc(a)
Definition: astmm.h:91
const ast_string_field queue_quantity1
Definition: app_queue.c:1266
struct ast_data * ast_data_add_str(struct ast_data *root, const char *childname, const char *string)
Add a string node type.
Definition: data.c:2401
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:2130
Asterisk module definitions.
static int manager_pause_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:8178
unsigned int no_hangup_chan
Definition: pbx.h:343
static int is_our_turn(struct queue_ent *qe)
Check if we should start attempting to call queue members.
Definition: app_queue.c:4324
#define queues_t_unlink(c, q, tag)
Definition: app_queue.c:1475
struct ast_channel * ast_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *status)
Requests a channel.
Definition: channel.c:5695
Device Name Used by AST_EVENT_DEVICE_STATE_CHANGE Payload type: STR.
Definition: event_defs.h:107
union ast_frame::@172 data
int callscompleted
Definition: app_queue.c:1297
struct ast_channel_tech * tech
Definition: channel.h:743
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2590
static int valid_exit(struct queue_ent *qe, char digit)
Check for valid exit from queue via goto.
Definition: app_queue.c:2815
static int shared_lastcall
queues.conf [general] option
Definition: app_queue.c:1070
static int queues_data_provider_get(const struct ast_data_search *search, struct ast_data *data_root)
Definition: app_queue.c:9022
Persistant data storage (akin to *doze registry)
struct ast_data * ast_data_add_int(struct ast_data *root, const char *childname, int value)
Add an integer node type.
Definition: data.c:2322
static char * handle_queue_pause_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:8511
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:253
struct ast_event_sub * ast_event_unsubscribe(struct ast_event_sub *event_sub)
Un-subscribe from events.
Definition: event.c:987
ast_context: An extension context
Definition: pbx.c:955
void ast_cdr_setdestchan(struct ast_cdr *cdr, const char *chan)
Set the destination channel, if there was one.
Definition: cdr.c:812
const ast_string_field sound_callerannounce
Definition: app_queue.c:1266
int announcefrequency
Definition: app_queue.c:1289
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:247
#define ao2_unlink(arg1, arg2)
Definition: astobj2.h:817
this call was forwarded somewhere else
Definition: cel.h:98
static char * app_upqm
Definition: app_queue.c:1047
#define QUEUE_EVENT_VARIABLES
Definition: app_queue.c:1210
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2599
int ast_cdr_init(struct ast_cdr *cdr, struct ast_channel *chan)
Initialize based on a channel.
Definition: cdr.c:897
int ast_data_search_match(const struct ast_data_search *search, struct ast_data *data)
Check the current generated node to know if it matches the search condition.
Definition: data.c:1458
static int manager_remove_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:8144
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1164
time_t lastcall
Definition: app_queue.c:1187
const ast_string_field language
Definition: channel.h:787
uint32_t version
Structure version.
Definition: data.h:247
struct ast_context * ast_context_find(const char *name)
Find a context.
Definition: pbx.c:2971
unsigned int stillgoing
Definition: app_queue.c:1138
char announce[PATH_MAX]
Definition: app_queue.c:1146
static const char * int2strat(int strategy)
Definition: app_queue.c:1353
char exten[AST_MAX_EXTENSION]
Definition: channel.h:869
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:128
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:437
static int queue_persistent_members
queues.conf [general] option
Definition: app_queue.c:1058
static int reload_queues(int reload, struct ast_flags *mask, const char *queuename)
reload the queues.conf file
Definition: app_queue.c:7477
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:2367
static char * complete_queue_show(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:7844
#define RESULT_FAILURE
Definition: cli.h:41
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:989
static int clear_stats(const char *queuename)
Facilitates resetting statistics for a queue.
Definition: app_queue.c:7542
The structure of the node handler.
Definition: data.h:245
static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
Place a call to a queue member.
Definition: app_queue.c:3565
int ringcount
Definition: app_queue.c:1190
static void queues_data_provider_get_helper(const struct ast_data_search *search, struct ast_data *data_root, struct call_queue *queue)
Definition: app_queue.c:8916
int ast_manager_unregister(char *action)
Unregister a registered manager command.
Definition: manager.c:5355
jack_status_t status
Definition: app_jack.c:143
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
char state_exten[AST_MAX_EXTENSION]
Definition: app_queue.c:1176
static int update_cdr
queues.conf [general] option
Definition: app_queue.c:1076
static struct @53 queue_results[]
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:9663
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: config.c:2650
char userfield[AST_MAX_USER_FIELD]
Definition: cdr.h:125
#define CONFIG_STATUS_FILEUNCHANGED
Definition: config.h:51
char * key
Definition: astdb.h:32
int pbx_builtin_serialize_variables(struct ast_channel *chan, struct ast_str **buf)
Create a human-readable string, specifying all variables and their corresponding values.
Definition: pbx.c:10444
int strategy
Definition: app_queue.c:998
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:344
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
Definition: config.c:2587
void ast_cdr_busy(struct ast_cdr *cdr)
Busy a call.
Definition: cdr.c:753
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:292
const char * name
Definition: app_queue.c:999